简体   繁体   English

响应备忘录组件并在将函数作为道具传递时重新渲染

[英]React memo components and re-render when passing function as props

Suppose I have these React components: 假设我有这些React组件:

const Compo1 = ({theName}) => {
  return (
    <Nested foo={() => console.log('Dr. ' + theName)}/>
  );
};

const Compo2 = ({theName}) => {
  function theFoo() {
    console.log('Dr. ' + theName);
  }
  return (
    <Nested foo={theFoo}/>
  );
};

And the nested component, wrapped in memo : 和嵌套组件,包含在memo

const Nested = React.memo(({foo}) => {
  return (
    <Button onClick={foo}>Click me</Button>
  );
});

Function passed in foo is always recreated in Compo1 and also Compo2 , correct? foo传递的函数总是Compo1Compo2 重新创建Compo1吗?

If so, since foo receives a new function every time, does it mean memo will be useless, thus Nested will always be re-rendered? 如果是这样,因为foo每次都会收到一个新函数,它是否意味着memo将无用,因此Nested将永远重新渲染?

You can use new hooks Api(React >= 16.8) to avoid recreating callback func. 您可以使用新的钩子Api(React> = 16.8)来避免重新创建回调函数。

Just using useCallback hook for this. 只需使用useCallback钩子。

For eg 例如

Parent component 父组件

import React, { useCallback} from 'react';

const ParentComponent = ({theName}) => {
  const theFoo = () => {
    console.log('Dr. ' + theName);
  }

  const memoizedCallback = useCallback(theFoo , []);

  return (
     <Nested foo={memoizedCallback}/>
   );
};

useCallback will return a memoized version of the callback that only changes if one of the dependencies has changed (which passed in the second argument) In this case we pass empty array as dependencies and therefore the function will be created only once. useCallback将返回一个回调的memoized版本,该版本只在其中一个依赖项发生更改时才会更改(在第二个参数中传递)。在这种情况下,我们将空数组作为依赖项传递,因此该函数只会创建一次。

And nested component: 和嵌套组件:

import React, { memo } from 'react';

const Nested = ({foo}) => (
  <Button onClick={foo}>Click me</Button>
);

export default memo(Nested);

For more info - https://reactjs.org/docs/hooks-reference.html#usecallback 有关详细信息, 请访问https://reactjs.org/docs/hooks-reference.html#usecallback

The memo function will shallow compare every different props, including functions. memo功能将浅显比较每个不同的道具,包括功能。 However, by redefining your function inside your components in every render, you will create a different reference every time, triggering a re-render. 但是,通过在每个渲染中重新定义组件内部的函数,每次都会创建一个不同的引用,从而触发重新渲染。

Although, as your can see in Comp3 , you can still use memo and avoid re-rendering by declaring an external function : 虽然,正如您在Comp3看到的那样,您仍然可以使用备忘录并通过声明外部函数来避免重新渲染:

 class App extends React.Component { constructor(props) { super(props) this.state = { } } componentDidMount = () => { setInterval(() => { this.setState({ e: true }) }, 2000) } render() { return ( <div> <Compo1 /> <Compo2 /> <Compo3 /> </div> ) } } const Compo1 = () => <Nested foo={() => console.log('Comp1 rendering')} /> const Compo2 = () => { function theFoo() { console.log('Comp2 rendering'); } return <Nested foo={theFoo} /> }; const foo3 = function (text) { console.log('Comp3 rendering ' + text) } const Compo3 = () => <Nested foo={foo3} /> const Nested = React.memo(({ foo }) => { foo('a param') return <div /> }) ReactDOM.render(<App />, document.getElementById('root')) 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script> <div id='root'> 

The nicest way I found was to use useRef . 我找到的最好的方法是使用useRef Specifically I use this structure together with Formik to prevent re-rendering of a long list of input values. 具体来说,我将此结构与Formik一起使用,以防止重新呈现一长串输入值。

const MyMemoizedGroupList = React.memo(
  ({
    groups,
    arrayHelpersRef,
  }) => {
    // [..] stuff
  }
}

function MainComponent() {
  const groupsArrayHelpersRef = React.useRef();

  return (
    <Formik 
      // [..] stuff
      render={({ values }) => (
        <Form>
          <FieldArray
            name="groups"
            render={arrayHelpers => {
              groupsArrayHelpersRef.current = arrayHelpers;
            }}
          />
          <MyMemoizedGroupList 
            groups={values.groups} 
            arrayHelpersRef={groupsArrayHelpersRef} 
          /> 
          {/* [..] stuff */}
        </Form>
      )} 
    />
  );
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM