【问题标题】:Consumers re-render when Provider re-renders当 Provider 重新渲染时,Consumer 重新渲染
【发布时间】:2019-01-25 16:05:15
【问题描述】:

根据react docs

每次 Provider 重新渲染时,下面的代码都会重新渲染所有消费者,因为总是为值创建一个新对象

所以我做了一个简单的例子来测试这个:

class App extends React.Component {

constructor(props) {
    super(props);
    this.state = {
      value: {something: 'something'},
    };
  }
  render() {
   console.log('App');
    return (
    <>
      <ThemeContext.Provider value={this.state.value}>
      <ThemeContext.Consumer>
       {(value)=>( <Toolbar test={value}/>)}
      </ThemeContext.Consumer>
      </ThemeContext.Provider>
      <button onClick={this.handler}>click me</button>
      </>
    );
  }

  handler=()=>{
  this.forceUpdate()
  }
}

const app =  <App />;

class Toolbar extends React.Component {
  render() {
   console.log('Toolbar');
    return (
     <div></div>
    );
  }
}

ReactDOM.render(app,mountNode);

似乎在每次点击中,即使引用相同,工具栏组件也会与提供程序一起重新呈现。那么这里有什么问题呢?

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

    将消费者编写为 App 的直接子级将导致它们在 App 组件重新呈现时呈现,而您必须将代码编写为

    const ThemeContext = React.createContext();
    class App extends React.Component {
    
      constructor(props) {
        super(props);
        this.state = {
          value: {something: 'something'},
        };
      }
      render() {
       console.log('App');
        return (
         <React.Fragment>
          <ThemeContext.Provider value={this.state.value}>
              {this.props.children}
          </ThemeContext.Provider>
          <button onClick={this.handler}>click me</button>
          </React.Fragment>
        );
      }
    
      handler=()=>{
        this.forceUpdate()
      }
    }
    
    const app =  (<App>
                   <ThemeContext.Consumer>
                      {(value)=>( <Toolbar test={value}/>)}
                    </ThemeContext.Consumer>
                 </App>)
    
    class Toolbar extends React.Component {
      render() {
       console.log('Toolbar');
        return (
         <div></div>
        );
      }
    }
    ReactDOM.render(app, document.getElementById('app'));
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.0/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.0/umd/react-dom.production.min.js"></script>
    <div id="app"/>

    【讨论】:

    • 它有效,但这里 Consumer 又是 Provider 的直接子代,对吧?
    • 不直接在树中
    • --APP --PROVIDER --CONSUMER --TOOLBAR DIV TOOLBAR-- CONSUMER-- PROVIDER-- APP--。这是在两种情况下(我的示例和您的示例)都由 react 生成的树,它完全相同。不触发消费者渲染的区别是什么?
    【解决方案2】:

    试试这个:

    class App extends React.Component {
    
    constructor(props) {
        super(props);
        this.state = {
          value: {something: 'something'},
        };
      }
    
       handler(){
        this.forceUpdate()
        }
    
      render() {
       console.log('App');
        return (
        <div>
          <ThemeContext.Provider value={this.state.value}>
          <ThemeContext.Consumer>
           {(value)=>( <Toolbar test={value}/>)}
          </ThemeContext.Consumer>
          </ThemeContext.Provider>
          <button onClick={this.handler}>click me</button>
          </div>
        );
      }
    
    
    }
    
    const app =  <App />;
    
    class Toolbar extends React.Component {
      render() {
       console.log('Toolbar');
        return (
         <div></div>
        );
      }
    }
    
    ReactDOM.render(app,mountNode);
    

    【讨论】:

    • 添加 div 元素而不是 并且改变你的内联函数是我的改变。
    猜你喜欢
    • 2021-03-12
    • 2016-12-30
    • 2018-08-12
    • 2019-06-01
    • 2021-12-18
    • 2021-04-14
    • 2018-10-07
    • 2011-08-30
    • 1970-01-01
    相关资源
    最近更新 更多