Reactjs 如何避免以基于React类的组件作为父级的无状态组件中出现不必要的更新

Reactjs 如何避免以基于React类的组件作为父级的无状态组件中出现不必要的更新,reactjs,react-hooks,react-lifecycle,react-lifecycle-hooks,Reactjs,React Hooks,React Lifecycle,React Lifecycle Hooks,我正在学习React,我发现React.memo()“不起作用”,因为我对基于父类的组件所做的每次更新都会重新呈现我的组件。但问题是组件上的道具不会改变,至少对我来说是有意义的 我使用useEffect钩子在屏幕上打印并重新渲染,尽管我使用React.memo(Men) const-Men=props=>{ useffect(()=>{ 控制台日志(“呈现”); }); 返回{props.adder}; }; 反应。备忘录(人); 类应用程序扩展了React.Component{ 状态={ 柜台

我正在学习React,我发现React.memo()“不起作用”,因为我对基于父类的组件所做的每次更新都会重新呈现我的组件。但问题是组件上的道具不会改变,至少对我来说是有意义的

我使用useEffect钩子在屏幕上打印并重新渲染,尽管我使用React.memo(Men)

const-Men=props=>{
useffect(()=>{
控制台日志(“呈现”);
});
返回

{props.adder}

; }; 反应。备忘录(人); 类应用程序扩展了React.Component{ 状态={ 柜台:0,, 加法器:“按” }; 添加=()=>{ this.setState(prevState=>{ 返回{ 计数器:prevState.counter+1 }; }); }; render(){ 返回( {this.state.counter}

); } }

我希望在我的控制台中,useEffect钩子中的消息“rendered”只出现一次。

React钩子也会使用依赖项数组,如果没有它,useEffect钩子将在每次渲染时激发其效果

memo
HOC函数还可以使用相等比较函数来进一步测试何时应该进行重新渲染,但请注意,react仍然控制何时进行重新渲染。HOCs(高阶组件)包装组件并返回要渲染的新组件。可以包装组件,但不保存返回的值以供以后渲染

const MemoizedComponent = React.memo(Component, [optional prop compare function]);
...
render() {
  return (
    <MemoizedComponent />
  );
};
const MemoizedComponent=React.memo(组件,[可选的属性比较函数]);
...
render(){
返回(
);
};

这是由于您如何使用
memo
-您需要使用
React.memo(Men)
提供的返回值

像这样:

正确:

const MenBefore = props => {
  React.useEffect(() => {
    console.log("rendered");
  });
  return <p onClick={props.add}>{props.adder}</p>;
};
////////////////////////////////////////
const Men = React.memo(MenBefore); // <--- THIS LINE
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

class App extends React.Component {
  state = {
    counter: 0,
    adder: "Click Me - I will -NOT- cause a re-render"
  };

  add = _ => {
    this.setState(prevState => {
      return {
        counter: prevState.counter + 1
      };
    });
  };

  render() {
    return (
      <div className="App">
        <p>{this.state.counter}</p>
        <Men adder={this.state.adder} add={this.add} />
      </div>
    );
  }
}

ReactDOM.render(<App />, document.body);
const Men = props => {
  React.useEffect(() => {
    console.log("rendered");
  });
  return <p onClick={props.add}>{props.adder}</p>;
};
/////////////////////////////
React.memo(Men); // <<<--------- WRONG
// ^^^^^^^^^^^^^^^^^^^^^^^^^^

class App extends React.Component {
  state = {
    counter: 0,
    adder: "Click Me - I will cause a re-render"
  };

  add = _ => {
    this.setState(prevState => {
      return {
        counter: prevState.counter + 1
      };
    });
  };

  render() {
    return (
      <div className="App">
        <p>{this.state.counter}</p>
        <Men adder={this.state.adder} add={this.add} />
      </div>
    );
  }
}

ReactDOM.render(<App />, document.body);
const MenBefore=props=>{
React.useffect(()=>{
控制台日志(“呈现”);
});
返回

{props.adder}

; }; //////////////////////////////////////// const Men=React.memo(MenBefore);//{ this.setState(prevState=>{ 返回{ 计数器:prevState.counter+1 }; }); }; render(){ 返回( {this.state.counter}

); } } render(,document.body);
不正确:

const MenBefore = props => {
  React.useEffect(() => {
    console.log("rendered");
  });
  return <p onClick={props.add}>{props.adder}</p>;
};
////////////////////////////////////////
const Men = React.memo(MenBefore); // <--- THIS LINE
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

class App extends React.Component {
  state = {
    counter: 0,
    adder: "Click Me - I will -NOT- cause a re-render"
  };

  add = _ => {
    this.setState(prevState => {
      return {
        counter: prevState.counter + 1
      };
    });
  };

  render() {
    return (
      <div className="App">
        <p>{this.state.counter}</p>
        <Men adder={this.state.adder} add={this.add} />
      </div>
    );
  }
}

ReactDOM.render(<App />, document.body);
const Men = props => {
  React.useEffect(() => {
    console.log("rendered");
  });
  return <p onClick={props.add}>{props.adder}</p>;
};
/////////////////////////////
React.memo(Men); // <<<--------- WRONG
// ^^^^^^^^^^^^^^^^^^^^^^^^^^

class App extends React.Component {
  state = {
    counter: 0,
    adder: "Click Me - I will cause a re-render"
  };

  add = _ => {
    this.setState(prevState => {
      return {
        counter: prevState.counter + 1
      };
    });
  };

  render() {
    return (
      <div className="App">
        <p>{this.state.counter}</p>
        <Men adder={this.state.adder} add={this.add} />
      </div>
    );
  }
}

ReactDOM.render(<App />, document.body);
const-Men=props=>{
React.useffect(()=>{
控制台日志(“呈现”);
});
返回

{props.adder}

; }; /////////////////////////////
反应。备忘录(人);//不过,这就是重点。
Men
组件不应在每次单击时重新呈现……因此,
useffect
不应在每次单击时触发,但它是……由于
memo
未正确使用……啊,是的,OP也误用了memo HOC。这方面的问题有点不清楚。OP使用的是HOC,只是不正确。OP需要使用React.memo(Men)
中的返回值,而不仅仅是使用HOC并尝试使用相同的组件。在这个场景中,
React.memo(Men)
基本上什么都不做。通常这不是问题,因为您将执行以下操作:
export default React.memo(Men)
,但在这种情况下,您必须使用来自
React.memo(Men)
的返回,请参阅我的答案,其中包含两个代码笔,显示这一点。这不是如何使用
useffect
的问题。好的,我不是那个对钩子或
memo
如何工作感到困惑的人。你为什么要向我解释我的答案?我的回答也有助于解释为什么他们对
useffect
的使用也会激发OP观察到的每个意外结果。因为
useffect
与此上下文无关<代码>使用效果
将在每次渲染时触发,如果未正确记忆。正确使用
memo
时,在OP的代码中,
useffect
不会在每次单击时触发,只是因为
memo
阻止了重新渲染。因此,
useffect
是由于不正确地使用了
memo
,而不是由于
useffect
的工作方式,也不是
useffect
导致这种行为,也不是“意外的”。。这是一个很好的解释,但在这种情况下并不重要。只是想帮忙。。。。。干杯