#reactjs #typescript
#reactjs #typescript
Вопрос:
Я столкнулся с ошибкой:
react-dom.development.js:23093 Ошибка без обнаружения: превышена максимальная глубина обновления. Это может произойти, когда компонент повторно вызывает setState внутри componentWillUpdate или componentDidUpdate. React ограничивает количество вложенных обновлений, чтобы предотвратить бесконечные циклы.
Я понимаю, что проблема может быть связана с тем, что я вызываю функции checkError и validationPassed, которые изменяют состояние через useReducer, в функции checkValidations, которая вызывается через перехват useEffect, но я не знаю, как это решить
Код выглядит так:
interface ValidationField {
errorMessage?: string;
focused: boolean;
hasError: boolean;
}
interface ClientEditorState {
client: Client;
validations: { [key in keyof Client]: ValidationField };
}
enum clientEditorActions {
UPDATE_ENTITY = 'CLIENT_EDITOR/UPDATE_ENTITY',
UPDATE_FOCUSED = 'CLIENT_EDITOR/UPDATE_FOCUSED',
VALIDATION_ERROR = 'CLIENT_EDITOR/VALIDATION_ERROR',
VALIDATION_PASSED = 'CLIENT_EDITOR/VALIDATION_PASSED',
}
interface UpdateEntityAction extends Action<typeof clientEditorActions.UPDATE_ENTITY> {
name: string;
value: string | boolean;
}
interface UpdateFocusedAction extends Action<typeof clientEditorActions.UPDATE_FOCUSED> {
name: string;
}
interface ValidationErrorAction extends Action<typeof clientEditorActions.VALIDATION_ERROR> {
message: string;
name: string;
}
interface ValidationPassedAction extends Action<typeof clientEditorActions.VALIDATION_PASSED> {
name: string;
}
type ClientEditorActions = UpdateEntityAction | UpdateFocusedAction | ValidationErrorAction | ValidationPassedAction;
const clientReducer: Reducer<ClientEditorState, ClientEditorActions> = (prevState, action) => {
switch (action.type) {
case clientEditorActions.UPDATE_ENTITY:
const clientUpdated = _cloneDeep(prevState || ({} as Client));
_set(clientUpdated, `client.${action.name}`, action.value);
return clientUpdated;
case clientEditorActions.UPDATE_FOCUSED:
const validationField = _cloneDeep(prevState);
_set(validationField, `validations.${action.name}.focused`, true);
return validationField;
case clientEditorActions.VALIDATION_ERROR:
const errorField = _cloneDeep(prevState);
_set(errorField, `validations.${action.name}.hasError`, true);
_set(errorField, `validations.${action.name}.errorMessage`, action.message);
return errorField;
case clientEditorActions.VALIDATION_PASSED:
const passed = _cloneDeep(prevState);
_set(passed, `validations.${action.name}.hasError`, false);
_set(passed, `validations.${action.name}.errorMessage`, undefined);
return passed;
default:
return prevState;
}
};
...
const getInitialState = (): ClientEditorState => ({
client: entity as Client,
validations: {
firstName: {
focused: false,
hasError: false,
},
},
});
const [state, clientDispatch] = useReducer(clientReducer, getInitialState());
const checkError = useCallback((name: string, message: string) => {
clientDispatch({
type: clientEditorActions.VALIDATION_ERROR,
name,
message,
});
}, []);
const validationPassed = useCallback((name: string) => {
clientDispatch({
type: clientEditorActions.VALIDATION_PASSED,
name,
});
}, []);
const checkValidations = useCallback(
(c: Client) => {
let validation = false;
const { firstName } = state.validations;
if (!c.firstName amp;amp; firstName.focused) {
validation = false;
checkError('firstName', f('client.requiredFieldClient'));
} else {
validation = true;
validationPassed('firstName');
}
},
[checkError, f, state.validations, validationPassed],
);
const [clientUpdateHandler] = useDebouncedCallback((clientUpdated: Client) => {
dispatch(updateEntityEditor(clientUpdated));
}, 800);
useEffect(() => {
if (!_isEqual(state.client, entity)) {
clientUpdateHandler(state.client as Client);
}
const { firstName } = state.validations;
if (firstName.focused) checkValidations(state.client);
}, [checkValidations, clientUpdateHandler, entity, state.client, state.validations]);
Ответ №1:
Я понимаю, что проблема может быть связана с тем, что я вызываю функции checkError и validationPassed, которые изменяют состояние через пользовательский редактор, в функции checkValidations, которая вызывается через перехват useEffect
Да, точно. Попробуйте уменьшить ваши зависимости в useEffect и связанных функциях в useCallback. Любое из этих изменений приведет к повторному запуску useEffect.
Возвращаясь к вопросу, ваш эффект использования в настоящее время зависит от состояния.проверки. Поэтому всякий раз, когда state.validations изменяется, useEffect запускается повторно. Рассмотрите возможность выполнения
const { firstName } = state.validations;
вне useEffect и обратного вызова checkValidations. Это остановит его повторный запуск при каждом изменении state.validations.