Reactjs 反应-错误:超过最大更新深度-useReducer

Reactjs 反应-错误:超过最大更新深度-useReducer,reactjs,typescript,Reactjs,Typescript,我面临一个错误: react dom.development.js:23093未捕获错误:超出最大更新深度。当组件在componentWillUpdate或componentDidUpdate内重复调用setState时,可能会发生这种情况。React限制嵌套更新的数量以防止无限循环 我知道问题可能是因为我在通过useEffect钩子调用的checkValidations函数中调用了checkError和validationPassed函数,这些函数通过useReducer修改状态,但我不知道如

我面临一个错误:

react dom.development.js:23093未捕获错误:超出最大更新深度。当组件在componentWillUpdate或componentDidUpdate内重复调用setState时,可能会发生这种情况。React限制嵌套更新的数量以防止无限循环

我知道问题可能是因为我在通过useEffect钩子调用的checkValidations函数中调用了checkError和validationPassed函数,这些函数通过useReducer修改状态,但我不知道如何解决这个问题

守则如下:

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 && 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]);
接口验证字段{
errorMessage?:字符串;
重点:布尔;
hasrerror:布尔型;
}
接口ClientEditorState{
客户:客户;
验证:{[key-in-keyof-Client]:ValidationField};
}
枚举客户端编辑操作{
更新实体='客户端编辑器/更新实体',
UPDATE\u FOCUSED='CLIENT\u EDITOR/UPDATE\u FOCUSED',
验证错误='客户端编辑器/验证错误',
验证通过='客户端编辑器/验证通过',
}
接口updateTityAction扩展了操作{
名称:字符串;
值:字符串|布尔值;
}
接口UpdateFocusedAction扩展操作{
名称:字符串;
}
接口验证操作扩展了操作{
消息:字符串;
名称:字符串;
}
接口验证passedAction扩展操作{
名称:字符串;
}
键入ClientEditorActions=UpdateEntityAction | UpdateFocusedAction | ValidationErrorAction | ValidationPassedAction;
const clientReducer:Reducer=(prevState,action)=>{
开关(动作类型){
案例clientEditorActions.UPDATE\u实体:
const clientUpdated=_cloneDeep(prevState | |({}作为客户端));
_set(clientUpdated,`client.${action.name}`,action.value);
返回客户更新;
案例客户编辑操作。更新\u聚焦:
const validationField=\u cloneDeep(prevState);
_set(validationField,`validations.${action.name}.focused`,true);
返回validationField;
案例clientEditorActions.VALIDATION\u错误:
常量错误字段=_cloneDeep(prevState);
_set(errorField,`validations.${action.name}.hasError`,true);
_set(errorField,`validations.${action.name}.errorMessage`,action.message);
返回错误字段;
案例clientEditorActions.VALIDATION\u通过:
const passed=_cloneDeep(prevState);
_set(已通过,`validations.${action.name}.hasrerror`,false);
_set(已传递,`validations.${action.name}.errorMessage`,未定义);
返回通过;
违约:
返回状态;
}
};
...
const getInitialState=():ClientEditorState=>({
客户:作为客户的实体,
验证:{
名字:{
重点:错,
错误:错,
},
},
});
const[state,clientDispatch]=useReducer(clientReducer,getInitialState());
const checkError=useCallback((名称:string,消息:string)=>{
客户派遣({
类型:clientEditorActions.VALIDATION\u错误,
名称
消息
});
}, []);
const validationPassed=useCallback((名称:string)=>{
客户派遣({
类型:clientEditorActions.VALIDATION\u已通过,
名称
});
}, []);
const checkValidations=useCallback(
(c:客户)=>{
让验证=假;
const{firstName}=state.validations;
如果(!c.firstName&&firstName.focused){
验证=假;
checkError('firstName',f('client.requiredFieldClient');
}否则{
验证=真;
validationPassed('firstName');
}
},
[checkError,f,state.validations,validationPassed],
);
const[clientUpdateHandler]=UsedBouncedCallback((clientUpdated:Client)=>{
调度(更新标题编辑器(客户端更新));
}, 800);
useffect(()=>{
如果(!_isEqual(state.client,entity)){
clientUpdateHandler(state.client作为客户端);
}
const{firstName}=state.validations;
if(firstName.focused)检查验证(state.client);
},[checkValidations,clientUpdateHandler,entity,state.client,state.validations];
我知道问题可能是因为我调用了checkError和validationPassed函数,这些函数在通过useEffect钩子调用的checkValidations函数中通过useReducer修改状态

没错。尝试减少useEffect中的依赖项以及useCallback中的关联函数。这些更改中的任何一个都将导致useEffect重新运行

回到问题,您的useEffect当前取决于state.validations。因此,只要state.validations发生更改,useEffect就会重新运行。考虑做< /P>
const { firstName } = state.validations;
在useEffect和checkValidations回调之外。这将阻止它在state.validations每次更改时重新运行