LoginSignup
1
0

More than 5 years have passed since last update.

[Get started]から始めるReact開発:その3:Components and Props

Last updated at Posted at 2017-06-07

さらにReact

[Get started]から始めるReact開発:その1
[Get started]から始めるReact開発:その2:Rendering Elements
[Get started]から始めるReact開発:その3:Components and Props
[Get started]から始めるReact開発:その4(State and Lifecycle①
[Get started]から始めるReact開発:その4(State and Lifecycle②

Components and Props

コンポーネントはUIを独立した再利用できるピースに分けることができ、個別のそれぞれのピースについて考えることができます。

Functional and Class Components

コンポーネントを定義する最もシンプルな方法はjavascript関数を書くことです。

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

この関数はデータとしてのpropsオブジェクトを引数として利用し、React要素を返すのでReactコンポーネントとして妥当なものです。
私たちはそのようなコンポーネントのことを文字通りjavascript funnctionなので"functional"と呼びます。
あなたはまた、コンポーネントの定義にES6 classを使うこともできます。

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

上記二つのコンポーネントは、Reactという観点で見れば同じものです。
クラスについては次のセクションで議論するだろう追加の特徴がいくつかあります。
それまではfunctional componentについては簡潔に利用することにしましょう。

Rendering a Component

以前、私たちはDOMタグを代表するReact要素のみに出会っていました。

code
const element = <div />;

しかしながら、要素はユーザー定義コンポーネントも代表することができます。

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

ユーザー定義コンポーネントを代表する要素としてReactを見るときは、単一のオブジェクトとしてこのコンポーネントにJSX attributeを渡します。私たちはこのオブジェクトをpropsと呼びます。

例えば、このコードはページ上にHello, Saraを描画します。

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

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

CodePenで確認

この例で何が起こっているかをおさらいしましょう。

  1. まず<Welcome name="Sara" />と一緒にReactDOM.render()を呼び出します。
  2. Reactはpropsとして{name: 'Sara'}と一緒にWelcomeコンポーネントを呼びます。
  3. Welcomeコンポーネントは結果として<h1>Hello, Sara</h1>要素をを返します。
  4. React DOMは<h1>Hello, Sara</h1>に合うように効率的にDOMをアップデートします。

警告
コンポーネント名は大文字で始める。
例えば<div />はDOMタグを代表していますが、<Welcome />はコンポーネントを代表し、<Welcome />にスコープがあることを要求します。

Composing Components

コンポーネントはそれらのアウトプットの中で他のコンポーネントを参照できます。これによりどのレベルの詳細にも同じコンポーネント抽象化を使用できます。ボタン、フォーム、ダイアログ、スクリーン。Reactアプリは全て、それらはコンポーネントとして共通の表現がされます。
例えば、なんどもWelcomeをレンダリングするAppコンポーネントを作れます。

code
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 Appsは一番上にシングルAppコンポーネントを持っています。しかしながらもし、既にあるAppにReactを統合する場合は、ボタンのような小さいコンポーネントから逆さまに始まるかもしれないし、徐々にビュー階層の一番上に向かって作業をするかもしれません。

警告
コンポーネントは単一のルート要素を返さなければなりません。これは全ての<Welcome />要素を含むように<div>を追加する理由となります。

Extracting Components

小さなコンポーネントにコンポーネントを分割することを恐れないでください。
例えばCommentコンポーネントについて考えます。

code
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で試す

propsとしてauther(オブジェクト),text(文字列),date(date オブジェクト?)を受け入れて、ソーシャルメディア上でコメントを述べます。
このコンポーネントは全てネストされているため、変更が複雑になりますしそれ自体のいち部分を個別に再利用することも難しくなっています。それではここから幾つかのコンポーネントを抜き出してみましょう。

最初にAvatorを抜き取ってみましょう

code
function Avatar(props) {
  return (
    <img className="Avatar"
      src={props.user.avatarUrl}
      alt={props.user.name}
    />
  );
}

AvatorCommentの中でレンダリングされていることを知る必要はありません。これはautherではなくより一般的な名前としてのuserをpropに与えている理由です。

私たちはほんの少しだけコメントをすぐに単純化できます。

code
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>
  );
}

次に、私たちはuser's nameに隣接するAvatarをレンダリングするUserInfoコンポーネントを抜き取ってみましょう。

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

これはさらにCommentを単純化することができます。

code
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で確認

コンポーネントの抽出は最初は単調な仕事のように見えるが、再利用可能なコンポーネントのパレットを持つことは大きなアプリでこそうまくいく。
大まかに良い方法としては、あなたのUIの一部で幾つかの部品(ButtonPanelAvatar)を使用している場合や、それ自身(App, FeedStory, Comment)が十分に複雑な場合には、再利用可能なコンポーネントの良い候補となります。

Props are Read-Only

functionclassとしてコンポーネントを宣言したとしても、それ自身のpropsを変更してはいけません。sum関数について考えます。

code
function sum(a, b) {
  return a + b;
}

このような関数はそれらの入力の変更を行わず、いつも同じ入力に対して同じ結果を返すのでpureと呼ばれています。
対象的に、この関数は自身の入力を変更しているのでimpureです。

code
function withdraw(account, amount) {
  account.total -= amount;
}

Reactはとても柔軟ではありますが、一つ厳格なルールを持っています。

All React components must act like pure functions with respect to their props.
全てのReactコンポーネントはそれらのpropsを尊重し純粋関数のように動かなければならない。

もちろん、アプリケーションUIはダイナミックで時間とともに変わります。次のセクションではstateの新しいコンセプトを紹介しましょう。
Stateはこのルールに違反することなくユーザーアクションやネットワークレスポンスや他の何かしらに反応して時間とともにそれらの出力を変更することをReactコンポーネントに許します。

1
0
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
1
0