Railsエンジニアがフロントエンド開発に入門してみた

スタメンでエンジニアをしている田中です。 普段はRailsエンジニアとしてTUNAGの機能改善を行なっていますが、以前から挑戦したかったフロントエンド開発の機会をいただけたので、今回はフロントエンド開発に入門してみた感想を記述します。

フロントエンド開発環境

はじめに、スタメンのフロントエンド開発環境について説明します。スタメンのエンジニアが作っている『TUNAG』の技術的な解説にも一部記載がありますが、本記事ではフロントエンドにフォーカスを当てた内容で説明します。

使用言語

  • TypeScript: 3.5.3

主なライブラリ

  • React: 16.8.6
  • React-Router: 5.0.1
  • Redux: 4.0.4
  • Redux-Saga: 1.0.5
  • styled-components: 4.3.2
  • ESLint: 6.2.1
  • Jest: 24.9.0
  • Enzyme: 3.10.0

元々はJavaScriptで記述していたこともあり、TUNAG全体ではJavaScriptのコードが多いですが、新規に作成する機能に関してはTypeScriptで実装しています。また今後はJavaScriptで書かれたコードをTypeScriptで書き換えることを計画しています。

入門してみた感想

React Hooksでスッキリ書ける

React Hooksとは

フック (hook) は React 16.8 で追加された新機能です。state などの React の機能を、クラスを書かずに使えるようになります

引用:フックの導入 – React

数ヶ月前からスタメンでも利用できるようになりました!(導入までの苦労話はこちらから) これまでクラスコンポーネントのみで利用できたstateやライフサイクルメソッドが、React Hooksの登場により関数コンポーネントでも書けるようになります。

コード例として、全く同じ挙動をするコードをクラスコンポーネントで書いた場合と関数コンポーネントで書いた場合を並べてみました。

基本

  • クラスコンポーネント
class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}
  • 関数コンポーネント
const Welcome = (props) => {
  return <h1>Hello, {props.name}</h1>;
}

引用: コンポーネントと props – React

state

  • クラスコンポーネント
class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>
    );
  }
}
  • 関数コンポーネント
import React, { useState } from 'react';

const Example = () => {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

引用: ステートフックの利用法 – React

ライフサイクルメソッド

  • クラスコンポーネント
class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  componentDidMount() {
    document.title = `You clicked ${this.state.count} times`;
  }

  componentDidUpdate() {
    document.title = `You clicked ${this.state.count} times`;
  }

  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>
    );
  }
}
  • 関数コンポーネント
import React, { useState, useEffect } from 'react';

const Example = () => {
  const [count, setCount] = useState(0);

  // Similar to componentDidMount and componentDidUpdate:
  useEffect(() => {
    // Update the document title using the browser API
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

引用: 副作用フックの利用法 – React

ご覧いただいた通りですが、どの項目についても関数コンポーネントの方がスッキリと記述できます。React Hooksの話を聞いた当初は、「そんなに大きく変わるものなのかな・・・」と思っていましたが、実際に手を動かしてみるとシンプルで直感的に書けて良いな!ということがよく分かりました。

styled-componentsがとても良い

styled-componentsとはコードの中にstyleを記述するCSS in JSのライブラリの1つです。 下記のようにコードの中にスタイルを記述することが出来るので、具体的にどこにスタイルが適用されているか分かりやすいです。

import React from 'react';
import styled from 'styled-components';

const Title = styled.h1`
  font-size: 1.5em;
  text-align: center;
`;

const Wrapper = styled.section`
  padding: 4em;
`;

<Wrapper>
  <Title>Hello World, this is my first styled component!</Title>
</Wrapper>

また、コンポーネントの継承により、共通のスタイルを適用できます。

const Button = styled.button`
  padding: 12px;
  border-radius: 4px;
`;

const OKButton = styled(Button)`
  backgroud-color: blue;
`;

const NGButton = styled(Button)`
  backgroud-color: red;
`;

これまでスタイルを設定しても上手く適用できない場合、

  • idやclassの指定が間違っている
  • BEMの記述が間違っている
  • CSSの記述が間違っている

のようなエラーになりうる要因がいくつかありましたが、styled-componentsでは適用したい箇所に直接指定できるため、CSSの記述に注力するだけで良くなりました。また、コンポーネント単位で設定できるため、影響範囲が限定的となり、スタイルの変更がしやすくなりました。

CSSに対して「上手く適用できない」「修正時の影響範囲が分かりにくい」といった苦手意識を持っていましたが、styled-componentsによってCSSと仲良くなれそうな気がします!

ディレクトリ構成に悩む

Railsではrails newコマンドで基本的なディレクトリ構成が出来るため、生成されたとおりにファイルを配置すればよいのですが、Reactにおけるディレクトリ構成は開発者が設計する必要があります。そのため、世の中にはReduxの役割ごとに構成したり、Atomic Designに則った形で構成したりと様々なパターンが存在しています。

大雑把な説明となりますが、本記事を記述している時点における直近の開発では下記のような構成にしています。

  • Reduxの役割ごとにディレクトリを作成
  • Componentsディレクトリを作成し、その配下にcommonや各機能を入れる

過去の記事とは異なる構成となっているので、その時々のベストな構成をこれからも探す必要があるのだろうなと思いました。

おわりに

初めてのフロントエンド開発はReact Hooksやstyled-components、そしてTypeScriptによる静的型付けによって効率的に開発を進めることが出来ました。言語の違いのみならず、様々な点でRailsとは大きく違いましたが、その違いを楽しみつつ開発することが出来ました。

また今回の開発をきっかけにフロントエンド開発にも携わるようになり、自身の技術領域が広がりました。こうした挑戦の機会がスタメンでは数多くあるため、成長できる良い環境だと改めて思いました。

最後に、株式会社スタメンでは一緒に働くエンジニアを募集しています。ご興味のある方はぜひエンジニア採用サイトをご覧ください。