LoginSignup
10
16

More than 5 years have passed since last update.

React.jsでComponentsの分割をしてみる

Last updated at Posted at 2017-04-29

Components

コンポーネントを使用すると、UIを独立した再利用可能な部分に分割し、各部分について個別に考えることができます。概念的には、コンポーネントはJavaScript関数のようなものです。

関数とClassコンポーネント

コンポーネントを定義する最も簡単な方法は、JavaScript関数を記述することです。

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

この関数は、データとともに単一の "props"オブジェクト引数を受け取り、React要素を返すため、有効なReactコンポーネントです。このようなコンポーネントは、文字通りJavaScript関数であるため、「機能的」と呼んでいます。また、ES6クラスを使用してコンポーネントを定義することもできます。というか、これは現時点では古い書き方であり、古い書き方は、新しい書き方と共存しませんので、新しい書き方を学ぶべきです

class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

上記の2つの要素は、Reactの観点から見れば全く同等な機能を提供しあmす。クラスに関しては、こっちで説明されているいくつかの追加機能があり、ここで詳しく説明されているので。ここでは、機能部品を簡潔に使用します。

コンポーネントのレンダリング

以前は、DOMタグを表すReact要素のみに遭遇しましたが、

const element = <div />;

ただし、要素はユーザー定義のコンポーネントを表すこともできます。

const element = <Welcome name="Sara" />;

Reactは、ユーザ定義のコンポーネントを表す要素を見ると、JSX属性を単一のオブジェクトとしてこのコンポーネントに渡します。このオブジェクトを「props」と呼びます。たとえば、次のコードでは、ページに「Hello、Sara」と表示されます。

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

const element = <Welcome name="Sara" />;
ReactDOM.render(
  element,
  document.getElementById('root')
);

CodePenで試してみてください。

上記の例で何が起こっているのか見てみましょう

まずReactDOM.render()<Welcome name="Sara" /> エレメントを呼んでいます。次にWelcomeコンポーネントでは{name: 'Sara'}の値を参照しています。Welcomeコンポーネントは結果として<h1> Hello、Sara </ h1>エレメント(要素)を返します。React DOMは効率的に<h1>Hello, Sara</h1>DOMを更新して一致させます

注意点:

コンポーネント名は常に大文字で開始してください。
たとえば、<div />はDOMタグを表しますが、<Welcome />はコンポーネントを表し、
ウェルカムをスコープに入れる必要があります。

コンポーネントの作成

コンポーネントは、他のコンポーネントを参照できます。これにより、どの階層に位置するコンポーネントに対しても同じコンポーネントの抽象化を表現できます。ボタン、フォーム、ダイアログ、スクリーン:Reactアプリケーションでは、すべてがコンポーネントとして一般的に表現されます。たとえば、Welcomを何度もレンダリングするAppコンポーネントを作成できます。


function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

function App() {
  return (
    <div>
      //ここ
      <Welcome name="Sara" />
      <Welcome name="Cahal" />
      <Welcome name="Edite" />
    </div>
  );
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
);

CodePenで試してみてください。

通常、新しいReactアプリケーションには、一番上に1つのコンポーネントがあります。しかし、Reactを既存のアプリケーションに統合する場合、Buttonのような小さなコンポーネントでボトムアップを開始し、徐々にビュー階層の最上位に向かって作業を進めることができます。

注意:
コンポーネントは単一のルート要素を返す必要があるので、すべての<Welcome />要素を含むように<div>を追加しています

コンポーネントの抽出

たとえば、下記のようなコンポーネントを考えてみましょう。

function Comment(props) {
  return (
    <div className="Comment">
      <div className="UserInfo">
        <img className="Avatar"
          src={props.author.avatarUrl}
          alt={props.author.name}
        />
        <div className="UserInfo-name">
          {props.author.name}
        </div>
      </div>
      <div className="Comment-text">
        {props.text}
      </div>
      <div className="Comment-date">
        {formatDate(props.date)}
      </div>
    </div>
  );
}

CodePenで試してみてください。

大きなコンポーネントを小さなコンポーネントに分割するのを恐れない

全ソース

function formatDate(date) {
  return date.toLocaleDateString();
}

function Comment(props) {
  return (
    <div className="Comment">
      <div className="UserInfo">
        <img className="Avatar"
             src={props.author.avatarUrl}
             alt={props.author.name} />
        <div className="UserInfo-name">
          {props.author.name}
        </div>
      </div>
      <div className="Comment-text">
        {props.text}
      </div>
      <div className="Comment-date">
        {formatDate(props.date)}
      </div>
    </div>
  );
}

const comment = {
  date: new Date(),
  text: 'I hope you enjoy learning React!',
  author: {
    name: 'Hello Kitty',
    avatarUrl: 'http://placekitten.com/g/64/64'
  }
};


ReactDOM.render(
  <Comment
    date={comment.date}
    text={comment.text}
    author={comment.author} />,
  document.getElementById('root')
);

上記のコードではauthor(オブジェクト)、text(文字列)、 date(日付)をpropsとして受け取り、ソーシャルメディアのWebサイトにコメントを記述します。このコンポーネントは、すべてがネストされているため変更するのが難しく、個々の部分を再利用することも困難です。そこからいくつかのコンポーネントを抽出しましょう。まず、「アバター」を抽出します。

function Avatar(props) {
  return (

    //ここ
    <img className="Avatar"
      src={props.user.avatarUrl}
      alt={props.user.name}
    />
  //ここ

  );
}

AvatarCommentの中でレンダリングされていることを知る必要はありません。その支柱に authorではなくuserというより一般的な名前を与えたのはそのためです。

function Comment(props) {
  return (
    <div className="Comment">
      <div className="UserInfo">
        //ここ
        <Avatar user={props.author} />
        <div className="UserInfo-name">
          {props.author.name}
        </div>
      </div>
      <div className="Comment-text">
        {props.text}
      </div>
      <div className="Comment-date">
        {formatDate(props.date)}
      </div>
    </div>
  );
}

次に、ユーザーの名前の横にアバターを描画するUserInfoコンポーネントを抽出します。


function UserInfo(props) {
  return (
    //ここ
    <div className="UserInfo">
      <Avatar user={props.user} />
      <div className="UserInfo-name">
        {props.user.name}
      </div>
    </div>
  //ここ
  );
}

これにより、さらに単純化することができます。

function Comment(props) {
  return (
    <div className="Comment">
      //ここ
      <UserInfo user={props.author} />
   //ここ
      <div className="Comment-text">
        {props.text}
      </div>
      <div className="Comment-date">
        {formatDate(props.date)}
      </div>
    </div>
  );
}

CodePenで試してみてください。

コンポーネントの抽出は、最初は面倒な作業のように思えるかもしれませんが、再利用可能なコンポーネントのパレットを持つことは、より大きなアプリケーションを実現するときに役に立ちます。再利用可能なコンポーネントを創造することを意識しましょう。

参考

React.jsでComponentの分割をしてみる

10
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
16