【问题标题】:Child re-rendering because of function?孩子因为功能而重新渲染?
【发布时间】:2020-05-01 17:30:36
【问题描述】:

我无法在孩子不断重新渲染的这些概念中导航,因为我从父级传递了一个函数。这个父函数引用了一个编辑器的值,draftjs。

function Parent() {
    const [doSomethingValue, setDoSomethingValue] = React.useState("");
    const [editorState, setEditorState] = React.useState(
        EditorState.createEmpty()
    );

    const editorRef = useRef<HTMLInputElement>(null);

    const doSomething = () => {
        // get draftjs editor current value and make a fetch call
        let userResponse = editorState.getCurrentContent().getPlainText("\u0001");

        // do something with userResponse
        setDoSomethingValue(someValue);
    }

    return (
        <React.Fragment>
            <Child doSomething={doSomething} />
            <Editor
             ref={editorRef}
             editorState={editorState}
             onChange={setEditorState}
             placeholder="Start writing..." />
            <AnotherChild doSomethingValue={doSomethingValue}
        <React.Fragment>
    }

}

My Child 组件只是一个调用父级的 doSomething 的按钮,仅此而已。

doSomething 做它的事情,然后对状态进行更改,然后将其传递给 AnotherChild。

我的问题是,只要 editorState 更新(即每次您在编辑器中键入),我的子组件就会重新呈现。这不是不必要的吗?如果是这样,我怎么能避免这种情况?

如果我向 Child 组件传递一个字符串并利用 React.Memo,除非字符串发生更改,否则它不会重新渲染。

那么我在将函数传递给孩子时缺少什么? 我的孩子应该每次都重新渲染吗?

【问题讨论】:

    标签: reactjs typescript draftjs


    【解决方案1】:

    React 致力于参考更改检测以重新渲染组件。

    Child.js:把它包裹在React.memo下面,这样它就变成了Pure Component

    const Child = ({doSomething}) => <button onClick={doSomething}>Child Button Name</button>;
    export default React.memo(Child);
    

    Parent.js -&gt; doSomething:在每次(重新)渲染时,也会重新创建回调。使用useCallback,这样您的函数就不会在每次渲染时重新创建。

    const doSomething = React.useCallback(() => {
        let userResponse = editorState.getCurrentContent().getPlainText("\u0001");
        setDoSomethingValue(someValue);
    }, [editorState]);
    

    旁注

    在更广泛的方面,memo 是 HOC 并且使组件成为纯组件。 useMemo 是缓存函数输出的东西。而useCallback 缓存了函数的实例。

    希望对你有帮助。

    【讨论】:

      【解决方案2】:

      如果您不希望每次重新渲染父组件时都重新渲染您的组件,您应该查看useMemo

      这个函数只会在它的第二个参数改变时重新计算它的值(在你的例子中,你的组件)(这里,它唯一依赖的东西,doSomething())。

      function Parent() {
          const [editorState, setEditorState] = React.useState(
              EditorState.createEmpty()
          );
      
          const editorRef = useRef<HTMLInputElement>(null);
      
          const doSomething = () => {
              // get draftjs editor current value and make a fetch call
              let userResponse = editorState.getCurrentContent().getPlainText("\u0001");
      
              // do something with userResponse
          }
      
          const childComp = useMemo(() => <Child doSomething={doSomething} />, [doSomething])
      
          return (
              <React.Fragment>
                  {childComp}
                  <Editor
                   ref={editorRef}
                   editorState={editorState}
                   onChange={setEditorState}
                   placeholder="Start writing..." />
              <React.Fragment>
          }
      }
      

      如果doSomething 没有改变,你的组件不会重新渲染。

      如果您的函数正在执行大量计算,您可能还希望将 useCallback 用于您的函数,以避免在每次渲染组件时重新编译它:https://reactjs.org/docs/hooks-reference.html#usecallback

      【讨论】:

      • 所以 doSomething 在技术上正在发生变化,因为 userResponse 正在发生变化,不是吗?那么这种重新渲染是合理的吗?
      • 不,除非调用函数,否则不会执行函数中的代码,useMemo 不会根据函数包含或返回的内容更改其行为,只是它的引用。通过在您的子组件中放置一个简单的console.log 来尝试一下,您会注意到即使它的父组件重新渲染也不会调用它
      【解决方案3】:

      查看PureComponentuseMemoshouldComponentUpdate

      我还要添加,而不是传递函数来渲染顶级组件,而是传递值并稍后在组件树中定义函数。

      【讨论】:

      • 我在我的问题中添加了更多内容。我之所以将 doSomething 留在 Parent 中,是因为它设置了另一个组件 AnotherChild 正在使用的状态值。那么我以后还想在组件树中向下传递值和函数吗?
      【解决方案4】:

      如果你想避免不必要的重新渲染,你可以使用 React.memo 和钩子 useCallback。看看下面的sandbox。 button1 总是重新渲染,因为它需要一个未使用 useCallback 记忆的回调,并且 button2 只是第一次渲染,即使父级的状态已更改(查看控制台以检查重新渲染) .您必须在负责呈现按钮的子组件中使用 React.memo。

      希望对你有帮助。

      【讨论】:

        猜你喜欢
        • 2017-08-28
        • 1970-01-01
        • 2016-07-26
        • 1970-01-01
        • 2021-08-22
        • 2016-05-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多