Child re-rendering 因为函数?

Child re-rendering because of function?

在 child 保留 re-rendering 的地方,我无法理解这些概念,因为我正在向它传递来自 parent 的函数。这个 parent 函数引用了编辑器的值 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>
    }

}

我的 Child 组件只是一个调用 parent 的 doSomething 的按钮,仅此而已。

doSomething 做它的事情然后改变状态然后传递给另一个Child。

我的问题是,每当 editorState 更新时(即每次您在编辑器中键入时),我的 Child 组件 re-renders。那不是没有必要吗?如果是这样,我该如何避免呢?

如果我向 Child 组件传递一个字符串并利用 React.Memo,它不会 re-render 除非字符串发生变化。

那么我在将函数传递给 child 时遗漏了什么? 我的child应该每次都是re-rendering吗?

如果您不希望每次重新渲染您的父组件时都重新渲染您的组件,您应该看看 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

查看 PureComponentuseMemoshouldComponentUpdate

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

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

希望对您有所帮助。

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

Child.js:将其包裹在React.memo so it becomes Pure Component.

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

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

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

旁注

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

希望对您有所帮助。