React useMemo重新渲染问题

时间:2020-05-14 08:29:36

标签: reactjs

我正在尝试使用react-useMemo来防止组件重新呈现。但是不幸的是,它似乎并没有解决任何问题,我开始怀疑自己做错了什么

我的组件看起来像这样

function RowVal(props) {
  console.log('rendering');
  return (
    <Row toggleVals={props.toggleVals}>
      <StyledTableData centerCell>{props.num}</StyledTableData>
      <StyledTableData centerCell borderRight>
        {props.percentage}
      </StyledTableData>
    </Row>
  );
}
  • toggleVals是布尔值
  • num是一个整数
  • 百分比prop是浮点值

为了防止重新渲染-我将以下内容添加到了父组件中

function ChainRow(props) {
 const MemoizedRowVal = useMemo(
    () => (
      <RowVal
        num={props.num}
        percentage={props.percentage}
        toggleVals={props.toggleVals}
      />
    ),
    [props.toggleVals],
  );

  return (

   <div>{MemoizedRowVal}</div>
  )

}

但是,即使布尔值没有变化,该组件仍然保持重新渲染。

我在做错什么吗?

3 个答案:

答案 0 :(得分:1)

useMemo将阻止创建组件的新实例,并且如果props不变,也不会阻止其重新呈现

我认为您需要使用React.memo而不是useMemo

function ChainRow(props) {

  return (

   <div>
      <RowVal
        num={props.num}
        percentage={props.percentage}
        toggleVals={props.toggleVals}
      />
    </div>
  )

}

const RowVal = React.memo((props) => {
   // rowVal code here
});

React.memo还提供了第二个参数(areEqual),您可以使用它来对重新渲染进行更精细的控制

答案 1 :(得分:1)

在react中,我们通常将React.Memo用于您的用例。将其包装在子组件上。您可能将它与React.useMemo混淆了。他们是不同的。 Using useMemo instead of React.memo syntax issue 检查该答案。

您可以尝试类似的操作

function RowVal(props) {
  console.log('rendering');
  return (
    <Row toggleVals={props.toggleVals}>
      <StyledTableData centerCell>{props.num}</StyledTableData>
      <StyledTableData centerCell borderRight>
        {props.percentage}
      </StyledTableData>
    </Row>
  );
}

export default React.Memo(RowVal).

答案 2 :(得分:0)

您发布的代码没有任何问题,当ChainRow使用相同的道具进行渲染时,也没有RowVal的渲染。我在下面的示例代码段中复制了您的代码,以证明您描述问题中所要执行的代码不是它所执行的工作,并且您的“问题”很可能是由于您未在问题中发布的内容引起的。

const { useState, useMemo } = React;

function RowVal(props) {
  console.log('rendering RowVal');
  return <pre>{JSON.stringify(props)}</pre>;
}

function ChainRow(props) {
  const MemoizedRowVal = useMemo(
    () => (
      <RowVal
        num={props.num}
        percentage={props.percentage}
        toggleVals={props.toggleVals}
      />
    ),
    [props.num, props.percentage, props.toggleVals]
  );

  return <div>{MemoizedRowVal}</div>;
}
function App() {
  const [state, setState] = useState({
    num: 1,
    percentage: 1,
    toggleVals: 1,
  });
  console.log('render app (if unrelated will not re render RowVal)');
  return (
    <div>
      <button
        onClick={() => setState((state) => ({ ...state }))}
      >
        unrelated app re render
      </button>
      <button
        onClick={() =>
          setState((state) => ({
            ...state,
            num: state.num + 1,
          }))
        }
      >
        change num
      </button>
      <button
        onClick={() =>
          setState((state) => ({
            ...state,
            percentage: state.percentage + 1,
          }))
        }
      >
        change percentage
      </button>
      <button
        onClick={() =>
          setState((state) => ({
            ...state,
            toggleVals: state.toggleVals + 1,
          }))
        }
      >
        change toggleVals
      </button>
      <ChainRow
        num={state.num}
        percentage={state.percentage}
        toggleVals={state.toggleVals}
      />
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>


<div id="root"></div>

您的useMemo还缺少会导致stale closures的props.num和props.percentage依赖性。如果您使用create react app创建了应用程序,则linter应该告诉您,因为cra的较新版本具有exhaustive deps