技術と魚

雑感と備忘録

‹Child parent={this} /› はアリか

※ 思考実験です

Reactはpropsという制約的なコミュニケーション手段があるからこそ、メンテナンス性があがるというもの。*1 今日コンポーネント指向と呼ぶものは、「コンポーネントがpropsによって一意に形態が定まる」という基本的性質に保証されていると言っても良いでしょう。

ただ、アレもコレもpropsで切り崩してしまうとすごい勢いで面倒くさくなることがあります。特に、親がstateを s1, s2, s3, ..と持っていて、子に対して onS1Change, onS2Change, onS3Change, .. と渡していくケースです。

class Parent extends Component {
  handleS1Change = (..) => { this.setState({ s1: .. }); }
  handleS2Change = (..) => { this.setState({ s2: .. }); }
  handleS3Change = (..) => { this.setState({ s3: .. }); }

  render() {
    const { s1, s2, s3 } = this.state;
    return (
      <Child
        s1={s1}
        s2={s2}
        s3={s3}
        onS1Change={this.handleS1Change}
        onS2Change={this.handleS2Change}
        onS3Change={this.handleS3Change}
      />
    );
  }
}

class Child extends Component {
  render() {
    const { s1, s2, s3, onS1Change, onS2Change, onS3Change } = this.props;
    return (
      <div>
         <YourNiceInput value={s1} onChange={onS1Change} />
         <YourNiceInput value={s2} onChange={onS2Change} />
         <YourNiceInput value={s3} onChange={onS3Change} />
      </div>
    )
  }
}

そんな時に、めんどくさいので親そのものを渡せば、一個で終わります。きましたね。これですよ!

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

class Child extends Component {
  render() {
    const { parent } = this.props;
    return (
      <div>
         <YourNiceInput value={parent.state.s1} onChange={(..) => { parent.setState({ s1: .. }) }} />
         <YourNiceInput value={parent.state.s2} onChange={(..) => { parent.setState({ s2: .. }) }} />
         <YourNiceInput value={parent.state.s3} onChange={(..) => { parent.setState({ s3: .. }) }} />
      </div>
    )
  }
}

気になる点

ライフサイクルイベントやパフォチューが難しい

prevPropsから直前の親stateが取れないと思うので、こういうのを駆使する場合はむずいですね。

型がつかないのでは?

TS触らないのでわかりません。子の方から親に対して型I/F提供するのは良い戦略な気がするけどしらん。

parentに依存するというのはコンポーネント指向的にどうなの?

これが各所で使い回されるコンポーネントであれば100%駄目でしょう。 しかし実際には、親コンポーネントが確定しているケースは結構多いはずです。

暫定の結論

ライフサイクルまわりの懸念が少ないコンポーネントに対してなら、使っても良さそうではある。 ただし親確定の場合のみ。 parent渡しで始めて、必要になったら細かくするぐらいの方が開発速度は上がる気がする。

*1:Context APIという例外もある