5

Im trying to use react-useMemo to prevent a component from re-rendering. But unfortunately, it doesn't seem to solve anything and im beginning to wonder if im doing something wrong

my component looks something like this

function RowVal(props) {
  console.log('rendering');
  return (
    <Row toggleVals={props.toggleVals}>
      <StyledTableData centerCell>{props.num}</StyledTableData>
      <StyledTableData centerCell borderRight>
        {props.percentage}
      </StyledTableData>
    </Row>
  );
}
  • toggleVals is an boolean values
  • num is an integer
  • percentage prop is a floating point value

In order to prevent the re-render - i added the below to my parent component

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

  return (

   <div>{MemoizedRowVal}</div>
  )

}

But this component still keeps re-rendering despite there being no change in the boolean value.

Is there something im doing wrong?

4

3 回答 3

3

useMemo will prevent a new instance of the component being created and will not stop it from re-rendering if props didn't change

I think what you need is to use React.memo and not 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 also provides a second argument(areEqual) which you can use to have a more fineGrained control on re-rendering

于 2020-05-14T08:38:43.893 回答
1

in react we generally use React.Memo for your use case. wrap it around child component. you might be confusing it with React.useMemo . they are different. Using useMemo instead of React.memo syntax issue check that answer.

you can try something like,

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).
于 2020-05-14T08:54:57.200 回答
0

There was nothing wrong with the code you posted and there are no re renders of RowVal when ChainRow re renders with the same props. I copied your code in the example snippet below to demonstrate that what you describe the code in your question to be doing is not what it does and your "problem" is likely caused by something you didn't post in your question.

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>

Your useMemo also has missing dependencies of props.num and props.percentage that would cause stale closures. If you created the app with create react app then the linter should have told you as newer versions of cra have exhaustive deps

于 2020-05-14T12:11:23.323 回答