【问题标题】:react context rerenders every child of Provider?反应上下文重新渲染提供者的每个孩子?
【发布时间】:2020-08-19 07:08:34
【问题描述】:
    import React, { useReducer, useEffect ,Component} from "react";
    import ReactDOM from "react-dom";
    const AppContext = React.createContext();

import React from "react";

const withRandomColors = WrappedComponent => {
  return class RandomColors extends React.Component {
    constructor() {
      super();
      this.randomColors = [
        "red",
        "blue",
        "green",
        "cyan",
        "lavender",
        "skyblue",
        "orange",
        "pink",
        "yellow"
      ];
    }

    getRandomColors() {
      const num = Math.floor(Math.random() * 10) % 9;
      return this.randomColors[num];
    }

    render() {
       console.log("Rerendering wrapper Component");
      return <WrappedComponent randomColor={this.getRandomColors()} />;
    }
  };
};

class Number extends React.Component {
  constructor(props) {
    super(props);
  }

  componentDidMount() {}

  render() {
    console.log("rendering Number Component");
    return (
      <AppContext.Consumer>
        {({ number }) => {
          return (
            <div style={{ backgroundColor: `${this.props.randomColor}` }}>
              {number} <br />
            </div>
          );
        }}
      </AppContext.Consumer>
    );
  }
}

class Text extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
     console.log("rendering Text Component");
    return (
      <AppContext.Consumer>
        {({ text }) => (
          <div style={{ backgroundColor: `${this.props.randomColor}` }}>
            {text} <br />
          </div>
        )}
      </AppContext.Consumer>
    );
  }
}

const WrappedText=withRandomColors(Text);
const WrappedNumber=withRandomColors(Number);

class App extends Component {
  constructor() {
    super();
    this.state = {
      number: Math.random() * 100,
      text: "testing context api"
    };
  }

  updateNumber = () => {
    const randomNumber = Math.random() * 100;
    this.setState({ number: randomNumber });
  };

  render() {
    console.log("rendering app")
    return (
      <AppContext.Provider value={this.state}>
        <div>
          <h1>Welcome to React</h1>
          <WrappedNumber  />
          <WrappedText />
          <button onClick={this.updateNumber}>Change Number </button>
        </div>
      </AppContext.Provider>
    );
  }
}



ReactDOM.render(
  <App />,
  mountNode
);

当点击 ChangeNumber 按钮时控制台显示

rendering app

Rerendering wrapper Component

Rerendering Number Component

Rerendering wrapper Component

Rerendering Text Component

数字和文本的背景颜色会发生变化。

React 上下文应该只为提供者重新呈现消费者,对吗?为什么要重新渲染 Provider 的所有子节点?

我希望只有数字更改保持数字和文本的背景颜色相同,并在单击更改数字按钮后低于控制台输出,因为只有消费者应该重新呈现文本和数字组件。

rendering app

我错过了什么?

我从sandbox获取代码

【问题讨论】:

    标签: javascript reactjs react-component react-context


    【解决方案1】:

    WrappedNumberWrappedText 会在您更新 App 组件中的状态时重新渲染,因为在 Virtual DOM 中它们与 Provider 处于相同的层次结构中,并且当父组件更新时,子组件也会更新。

    为了避免它们重新渲染,您可以将它们作为 App 的子级提供

    class App extends Component {
      constructor() {
        super();
        this.state = {
          number: Math.random() * 100,
          text: "testing context api"
        };
      }
    
      updateNumber = () => {
        const randomNumber = Math.random() * 100;
        this.setState({ number: randomNumber });
      };
    
      render() {
        console.log("rendering app")
        return (
          <AppContext.Provider value={this.state}>
            <div>
              <h1>Welcome to React</h1>
              {this.props.children}
              <button onClick={this.updateNumber}>Change Number </button>
            </div>
          </AppContext.Provider>
        );
      }
    }
    
    ReactDOM.render(
      <App >
          <WrappedNumber  />
          <WrappedText />
     </App>,
      mountNode
    );
    

    【讨论】:

    • 好的。但是在创建 App 节点时我没有在运行时提供 WrappedText 和 WrappedNumber 儿童,而是在 App 的 render 方法中对它们进行了硬编码,但是两者都产生相同的结果,对吧?两者在反应如何处理这方面有什么区别吗?
    • 正如我所说,不同之处在于如何使用虚拟 DOM 处理它们。当组件由于 state 或 props 改变而重新渲染时,任何直接在其 render 方法中重新渲染的组件都会被重新渲染。然而,上下文变化是专门向消费者传播的。当您将组件移出到 App 的父级并将它们呈现为子道具时,当 App 由于状态更改而重新渲染时,它们不会重新渲染
    猜你喜欢
    • 1970-01-01
    • 2016-05-17
    • 1970-01-01
    • 2020-12-17
    • 1970-01-01
    • 2019-11-23
    • 2017-08-28
    • 1970-01-01
    • 2022-12-23
    相关资源
    最近更新 更多