Ребенка рендеринг из-за функции? - PullRequest
1 голос
/ 01 мая 2020

Мне трудно ориентироваться в этих понятиях, когда ребенок продолжает повторную визуализацию, потому что я передаю ему функцию от родителя. Эта родительская функция ссылается на значение редактора, draft js.

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>
    }

}

Компонент «Мой ребенок» - это просто кнопка, которая вызывает doSomething родительского объекта и вот так.

doSomething делает свое дело, а затем вносит изменения в состояние, которое затем передается в AnotherChild.

Моя проблема заключается в том, что каждый раз, когда editorState обновляется (то есть каждый раз, когда вы печатаете в редакторе) ), мой дочерний компонент перерисовывается. Разве это не нужно? И если так, как я мог избежать этого?

Если я передавал свой дочерний компонент строку и использовал React.Memo, он не рендерится, пока строка не изменится.

Так что же мне не хватает при передаче функции ребенку? Должен ли мой ребенок каждый раз перерисовываться?

Ответы [ 4 ]

0 голосов
/ 01 мая 2020

React работает над обнаружением изменения ссылки для повторного рендеринга компонентов.

Child.js: оберните его в React.memo , чтобы оно стало 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]);

Side Note

В более широких строках memo является HO C и делает компонент Pure Component. useMemo - это то, что кэширует выходные данные функции. Принимая во внимание, что useCallback кэширует экземпляр функции.

Надеюсь, это поможет.

0 голосов
/ 01 мая 2020

Взгляните на PureComponent, useMemo или shouldComponentUpdate

Я бы также добавил, вместо того, чтобы передавать функцию, выполняющую рендеринг компонента верхнего уровня, передавать значение и определите функцию позже в дереве компонентов.

0 голосов
/ 01 мая 2020

если вы хотите избежать ненужных повторных рендеров, вы можете использовать React.memo и хук useCallback. Взгляните на следующую песочницу . Button1 всегда перерисовывается, потому что он принимает обратный вызов, который не запоминается с помощью useCallback, а button2 просто визуализируется в первый раз, даже если состояние родительского элемента изменилось (посмотрите на консоль, чтобы проверить повторные визуализации) , Вы должны использовать React.memo в дочернем компоненте, который отвечает за отображение кнопок.

Надеюсь, это поможет.

0 голосов
/ 01 мая 2020

Если вы не хотите, чтобы ваш компонент перерисовывался каждый раз, когда перерисовывается ваш родитель, вы должны взглянуть на 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

...