LoginSignup
19
12

More than 5 years have passed since last update.

React.js の render-props と Function as child の紹介

Last updated at Posted at 2018-10-22

この記事は Meguro.es #17 のプレゼン資料です。SpeackerDeck に PDF をアップしましたが、ドキュメントのメンテは Qiita で行います。


目的

  • render-props とは何かを理解すること
  • Function as child とは何かを理解すること
  • render-props を使ったコードが読めるようになること
  • Function as child を使ったコードが読めるようになること

省略すること

  • SFC。すべてクラス構文に統一しました。
  • 「値」、「参照」といった用語の厳密な使い方
  • props の型

コンポーネント呼び出しの素朴な例

親コンポーネントが子コンポーネントを呼び出す、もっとも単純な例です。

class Parent extends Component {
  render() {
    return <Child />
  }
}

class Child extends Component {
  render() {
    return '子コンポーネント'
  }
}

親から子へ文字列を渡す

親コンポーネントは子コンポーネントに、JSX の属性として、文字列を渡すことができます。
JSX の属性 として指定することで、this.props でそれを参照することができます。

import React, { Component } from 'react'

class Parent extends Component {
  render() {
    const something = 'aaa'
    return <Child something={something} />
  }
}

class Child extends Component {
  render() {
    return <>something  {this.props.something}</>
  }
}

親から子へオブジェクトを渡す

親コンポーネントは子コンポーネントに、JSX の属性として、オブジェクトを渡すことができます。たとえば、{ keyA: 'aaa'} です。

class Parent extends Component {
  render() {
    const something = { keyA: 'aaa'}
    return <Child something={something} />
  }
}

class Child extends Component {
  render() {
    return <>something.keyA  {this.props.something.keyA}</>
  }
}

親から子へ関数を渡す

親コンポーネントは子コンポーネントに、JSX の属性として、関数を渡すことができます。
JSX の属性が関数なら、コールバックとして使えるということです。

class Parent extends Component {
  something() {
    console.log('aaaaaa')
  }
  render() {
    return <Child something={this.something} />
  }
}

class Child extends Component {
  render() {
    this.props.something()
    return <>子コンポーネント</>
  }
}

親から子へコンポーネントを返す関数を渡す

先程の例では、JSX の属性として渡した関数は、console.log を実行しただけでした。
コンポーネント(React.Element) を返すという使い方がもっと有益です。

たとえば、親コンポーネントで DOM 要素を返す関数を定義して、子コンポーネントの props として渡します。
そして、子コンポーネントの render メソッドの定義中でその関数を実行します。
次の例では、prop の名前を something から render に変更し、雰囲気をだしました。


class Parent extends Component {
  something() {
    return <>親コンポーネント</>
  }
  render() {
    return <Child render={this.something} />
  }
}

class Child extends Component {
  render() {
    return this.props.render()
  }
}

親から子へコンポーネントを渡す1

親コンポーネントは子コンポーネントに、JSX の属性として、コンポーネントを渡すことができます。

class WanderingComponents extends Component {
  render() {
    return <>WanderingComponents</>
  }
}

class Parent extends Component {
  render() {
    return <Child myComponent={<WanderingComponents />} />
  }
}

class Child extends Component {
  render() {
    return <>{this.props.myComponent}</>
  }
}

親から子へコンポーネントを渡す2

先程の例は、JSX の属性名を children にすると、Child コンポーネントはよくみるイディオムになります。

class WanderingComponents extends Component {
  render() {
    return <>WanderingComponents</>
  }
}

class Parent extends Component {
  render() {
    return <Child children={<WanderingComponents />} />
  }
}

class Child extends Component {
  render() {
    return <>{this.props.children}</>
  }
}

コンポーネントのネストと children 属性

親から子にコンポーネントを渡すとき、JSX の属性としてではなく、コンポーネントをネストさせる形で渡すこともできます。ネストさせると呼び出し側から属性名の記述が消えますが、children という名前で受け取れると規定されています
以下の書き方で、WanderingComponents は Child の子コンポーネントになるので、Child では this.props.children で WanderingComponents を取得できます。


class WanderingComponents extends Component {
  render() {
    return <>WanderingComponents</>
  }
}

class Parent extends Component {
  render() {
    return (
      <Child>
        <WanderingComponents />
      </Child>
    )
  }
}

class Child extends Component {
  render() {
    return this.props.children
  }
}

Function as child パターン

コンポーネントのネスト部が children 属性に対応するということを確認しました。
このコンポーネントのネスト部は、コンポーネントそのものだけではなく関数にすることもできます。
children 属性がコールバックとして使えるということです。
その場合、render での children 属性の呼び出しは {this.props.children} ではなく {this.props.children()} です。
これを「Function as child パターン」と呼びます。


class Parent extends Component {
  something() {
    return <>something</>
  }
  render() {
    return (
      <Child>
        {this.something}
      </Child>
    )
  }
}

class Child extends Component {
  render() {
    return this.props.children() // () をつけて関数を実行した
  }
}

Functions as Children と render-props の関係

一つ前の子コンポーネントの reunder メソッドは return this.props.children() という定義でした。
children 属性が関数である必要があると読み取れます。
これは JSX の属性として関数を渡す、いわゆる render-props です。

コンポーネントを返す関数を prop とする JSX の属性名を render から children に変更してみましょう。


render 版

import React, { Component } from 'react'

class Parent extends Component {
  something() {
    return <>something</>
  }
  render() {
    return <Child render={this.something} />
  }
}

class Child extends Component {
  render() {
    return this.props.render()
  }
}

children 版

import React, { Component } from 'react'

class Parent extends Component {
  something() {
    return <>something</>
  }
  render() {
    return <Child children={this.something} />
  }
}

class Child extends Component {
  render() {
    return this.props.children()
  }
}

挙動は同一です。
Functions as Children は render-props の一種だとみなせることがわかりました。


リファレンス

19
12
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
19
12