Использование крючков React для настройки состояния и локального хранилища, а также React говорит о том, что я делаю слишком много звонков

#reactjs #axios #react-hooks #local-storage

Вопрос:

У меня есть небольшой компонент React, который просто использует редактор расширенного текста(TinyMCE) для редактирования значений в текстовом поле, отображаемом в веб-приложении.

Я обнаружил, что если я печатаю слишком быстро или слишком много, я получаю эту ошибку:

Неперехваченная ошибка: Превышена максимальная глубина обновления. Это может произойти, когда компонент повторно вызывает setState внутри componentWillUpdate или componentDidUpdate.

Но я не использую ни componentWillUpdate то, ни другое componentDidUpdate

Поэтому я не уверен, почему React говорит мне это.

Я пытался починить, но ничего из того, что я делаю, не помогает.

Я был бы признателен за любую информацию! 🙂

Вот мой компонент реакции:

 import React, { useState, useEffect } from 'react';
import { Editor } from '@tinymce/tinymce-react';
import axios from 'axios';

const App = (props) => {
    const [engineText, setEngineTextState] = useState(props.engineText || "Describe your engine...");
    const [engineId, setEngineIdState] = useState(props.engineId);
    var edValue = '';

    // first check local storage to see if they already have typed something...use engineId as the unique key
    if (localStorage.getItem(engineId)) {
        edValue = localStorage.getItem(engineId);
    } else {
        edValue = engineText;
    }

    const [engineState, setEngineState] = useState(edValue);

    // set the local storage in case user navigates away and then comes back we don't lose what they wrote
    useEffect(() => {
        localStorage.setItem(engineId, engineState)
    }, [engineState]);

    // update database
    const updateEngineText = (content) => {
        const request = axios.put(`/api/EngineManagementConsole/${engineId}/engineText`, JSON.stringify(content), {
            headers: {
                'Content-Type': 'application/json'
            }
        });
        setEngineState(content);
    }
    return (
        <Editor
            initialValue={edValue}
            init={{
                height: 500,
                menubar: 'file edit view insert format tools table help',
                plugins: [
                    'searchreplace visualblocks code fullscreen',
                ]
            }}
            value={engineState}
            onEditorChange={updateEngineText}
        />
    )
}

export default App;
 

Ответ №1:

Ваш компонент будет проверять localStorage и устанавливать значение edValue для каждого отдельного рендеринга. Это передается в качестве initialValue реквизита Editor , поэтому это приведет Editor к повторному отображению компонента.

Поскольку это всего лишь начальное значение, вы, вероятно, хотели оценить его только один раз. Мы можем использовать useMemo это для этого.

Ваш edValue является производным от обоих engineId , и engineText поэтому они должны быть зависимостями useMemo . Он будет повторно оценен, если какая-либо из этих переменных изменится.

Кажется глупым дублировать реквизиты engineId и engineText как состояние, когда кажется, что вы нигде не обновляете их состояние. Просто используйте реквизит напрямую.

 const App = ({engineId, engineText = "Describe your engine..."}) => {

    const edValue = useMemo( () => {
         // function to create the value
         return localStorage.getItem(engineId) || engineText;
         // dependencies array
         }, [engineId, engineText]
    );

    const [engineState, setEngineState] = useState(edValue);
...
 

Примечание: Я не уверен, что это единственная проблема, могут быть и другие проблемы, вызывающие ошибку.

Комментарии:

1. Спасибо! Нужно ли мне избавляться от useEffect() того, что я использую? Кроме того, я также предполагаю, что мне больше не нужна эта строка: var edValue = ''; я проверю это! Спасибо!

2. Еще раз привет, так что я проверил это, и это больше не сбивает меня с толку. Это работает намного лучше, но я заметил, что когда я редактирую текст в компоненте, покидаю страницу, а затем возвращаюсь, текст все еще говорит "Describe your engine..." . Поэтому по какой-то причине он не получает новый текст из хранилища. Теперь, если я обновлю страницу, она получит новый текст. Поэтому я задаюсь вопросом, нужно ли мне вернуть useEffect() заявление обратно… потому что именно там у меня было localStorage.setItem ? Спасибо!

3. По-прежнему не везет 🙁 В итоге я не добавил это useEffect() утверждение обратно. Но я переместил функцию localStorage.setItem(engineId, engineState) в updateEngineText() функцию, думая, что это сработает. Однако он сохраняет правильный/обновленный текст в базе данных и локальном хранилище. Но по какой-то причине, когда я удаляюсь, а затем возвращаюсь, отображается «Опишите свой движок…» вместо того, что хранится в localStorage, пока я не обновлю страницу вручную.