如何避免将基于React类的组件作为父组件在无状态组件中进行不必要的更新

时间:2019-07-31 21:56:47

标签: reactjs react-hooks react-lifecycle react-lifecycle-hooks

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

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

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

    class App extends React.Component {
        state = {
          counter: 0,
          adder: "press"
        };

        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>
          );
        }
      }

我希望在控制台中,useEffect挂钩中的“已渲染”消息仅出现一次。

2 个答案:

答案 0 :(得分:1)

React钩子也接受一个依赖项数组,没有它,useEffect钩子将在每个渲染上触发其效果。 react hooks reference

useEffect(() => {
  console.log("rendered");
});  // every render

useEffect(() => {
  console.log("rendered");
}, []);  // on mount, once

useEffect(() => {
  console.log("rendered");
}, [propValue]);  // every time propValue is a new reference

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

const MemoizedComponent = React.memo(Component, [optional prop compare function]);
...
render() {
  return (
    <MemoizedComponent />
  );
};

答案 1 :(得分:1)

发生这种情况的原因是您使用memo的方式-您需要使用React.memo(Men)为您提供的返回值。

赞:

This CodePen will cause a re-render

This CodePen will NOT cause a re-render

正确:

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);