web-dev-qa-db-ja.com

React:親コンポーネントが再レンダリングするとき、子は常に再レンダリングしますか?

親コンポーネントが再レンダリングする場合、shouldComponentUpdate()を実装しない限り、そのすべての子が再レンダリングすることは私の知る限りです。 I 例を作成 これは真実ではないようです。

3つのコンポーネントがあります:_<DynamicParent/>_、_<StaticParent/>_、および_<Child/>_。 _<Parent/>_コンポーネントは_<Child/>_のレンダリングを担当しますが、さまざまな方法でレンダリングします。

_<StaticParent/>_のレンダリング関数は、次のように、実行前に_<Child/>_を静的に宣言します。

_ <StaticParent>
    <Child />
 </StaticParent>
_

_<DynamicParent/>_は、次のように、実行時に_<Child/>_の受信とレンダリングを動的に処理します。

_ <DynamicParent>
    { this.props.children }
 </DynamicParent>
_

_<DynamicParent/>_と_<StaticParent/>_の両方には、onClickリスナーがあり、クリックすると状態が変更されて再レンダリングされます。 _<StaticParent/>_をクリックすると、それと_<Child/>_の両方が再レンダリングされることに気付きました。しかし、_<DynamicParent/>_をクリックすると、親とNOT _<Child/>_のみが再レンダリングされます。

_<Child/>_はshouldComponentUpdate()のない機能コンポーネントなので、なぜ再レンダリングしないのか理解できません。誰かがこれが事実である理由を説明できますか?このユースケースに関連するドキュメントには何も見つかりません。

15
Gabriel West

コンテキストの実際のコードを投稿します。

_class Application extends React.Component {
  render() {
    return (
      <div>
        {/* 
          Clicking this component only logs 
          the parents render function 
        */}
        <DynamicParent>
          <Child />
        </DynamicParent>

        {/* 
          Clicking this component logs both the 
          parents and child render functions 
        */}
        <StaticParent />
      </div>
    );
  }
}

class DynamicParent extends React.Component {
  state = { x: false };
  render() {
    console.log("DynamicParent");
    return (
      <div onClick={() => this.setState({ x: !this.state.x })}>
        {this.props.children}
      </div>
    );
  }
}

class StaticParent extends React.Component {
  state = { x: false };
  render() {
    console.log("StaticParent");
    return (
      <div onClick={() => this.setState({ x: !this.state.x })}>
        <Child />
      </div>
    );
  }
}

function Child(props) {
  console.log("child");
  return <div>Child Texts</div>;
}
_

アプリケーションのレンダリングでこのコードを書くとき:

_<StaticParent />
_

レンダリングされるのはこれです:

_ <div onClick={() => this.setState({ x: !this.state.x })}>
    <Child />
 </div>
_

そして実際には、(大体)起こることはこれです:

_function StaticParent(props) {
  return React.createElement(
    "div",
    { onClick: () => this.setState({ x: !this.state.x }) },
    React.createElement(Child, null)
  );
}

React.createElement(StaticParent, null);
_

DynamicParentを次のようにレンダリングすると:

_<DynamicParent>
    <Child />
</DynamicParent>
_

これが実際に起こることです(大まかに言って)

_function DynamicParent(props) {
    return React.createElement(
        "div",
        { 
            onClick: () => this.setState({ x: !this.state.x }), 
            children: props.children 
        }
    );
}

React.createElement(
      DynamicParent,
      { children: React.createElement(Child, null) },
);
_

そして、これは両方の場合の子です:

_function Child(props) {
    return React.createElement("div", props, "Child Text");
}
_

これは何を意味するのでしょうか? StaticParentコンポーネントでは、StaticParentのrenderメソッドが呼び出されるたびにReact.createElement(Child, null)を呼び出しています。 DynamicParentの場合、子は一度作成され、小道具として渡されます。 _React.createElement_は純粋な関数なので、おそらくパフォーマンスのためにどこかにメモされているでしょう。

DynamicParentの場合にChildのレンダーを再度実行させるのは、Childの小道具の変更です。たとえば、親の状態が子の小道具として使用された場合、両方のケースで再レンダリングがトリガーされます。

ダン・アブラモフがこの答えを破棄するコメントに現れないことを本当に望んでいます。

14
SrThompson

主に2つの異なる「子供」がいる原因です。

  • this.props.children
  • <Child/>

それらは同じものではありません。最初のものはApplication -> DynamicParentから渡されたpropであり、2番目のものはComponentでレンダリングされたStaticParentです。個別のレンダリング/ライフサイクル。

含まれている例

class Application extends React.Component {
  render() {
    return (
      <div>
        {/* 
          Clicking this component only logs 
          the parents render function 
        */}
        <DynamicParent>
          <Child />
        </DynamicParent>

        {/* 
          Clicking this component logs both the 
          parents and child render functions 
        */}
        <StaticParent />
      </div>
    );
  }
}

文字通り同じです:

class Application extends React.Component {
  render() {
    // If you want <Child/> to re-render here
    // you need to `setState` for this Application component.
    const childEl = <Child />;
    return (
      <div>
        {/* 
          Clicking this component only logs 
          the parents render function 
        */}
        <DynamicParent>
          {childEl}
        </DynamicParent>

        {/* 
          Clicking this component logs both the 
          parents and child render functions 
        */}
        <StaticParent />
      </div>
    );
  }
}
4
Xlee