超过了UserReducer的更新深度,但未超过UseState

bybem2ql  于 2022-09-21  发布在  React
关注(0)|答案(1)|浏览(179)

我有一个useEffect,它在每次用户在输入中键入内容时触发。起初,我让它以useState运行,运行起来像黄油一样流畅,但我被要求将其更改为useReducer。UseReducer的useEffect:

useEffect(() => {
dispatch({type : 'username', payload : watch().username});
dispatch({type : 'password', payload : watch().password});
console.log(state.username, state.password);
}, [watch()]);

UseEffect with useState:

useEffect(() => {
setPassword(watch().password);
setUsername(watch().username);
console.log(username, password);
}, [watch()]);

而且,即使用户没有输入任何内容,useEffect也会不断地被触发,因为当与useState一起使用时,它不会这样做。

减速机:

const reducer = (state, action) => {
switch (action.type) {
  case "username":
    return {...state, username: action.payload };
  case "password":
    return {...state, password : action.payload};
}
};
kpbpu008

kpbpu0081#

这里有一些危险信号,但最突出的是您如何使用watch()useEffectuseState(可能)将在每次渲染时重新运行,因为watch()可能正在返回非备注对象。您的代码使用useState“工作”的原因是setting a state object to the same thing does nothing--如果用户名或密码没有更改,则状态不会更新,因此组件不会重新呈现。

useReducer并非如此,除非您在Reducer函数中显式地满足它--下面这样的代码可能会修复这个错误:

const reducer = (state, action) => {
  switch (action.type) {
    case "username":
      return state.username !== action.payload
        ? {...state, username: action.payload }
        : state;

    case "password":
      return state.password !== action.payload
        ? {...state, password: action.payload }
        : state;

    default: 
      return state;
  }
};

但是,您还应该尝试使挂钩的依赖项尽可能简单。有什么原因不能先调用watch(),然后将值传递给您的效果吗?

const { username, password } = watch();

useEffect(() => {
  dispatch({type : 'username', payload : username});
  dispatch({type : 'password', payload : password});
}, [username, password]);

或者,您可以更好地将两者分为两种不同的效果-如果password已更改,则无需发送username更新:

const { username, password } = watch();

useEffect(() => {
  dispatch({type : 'username', payload : username});
}, [username]);

useEffect(() => {
  dispatch({type : 'password', payload : password});
}, [password]);

而且,当我们处于重构模式时,为什么不创建一个定制钩子来为您处理逻辑呢?类似于:

const useLoginFormState = (formValues) => {
  const { username, password } = formValues;

  useEffect(() => {
    dispatch({type : 'username', payload : username});
  }, [username]);

  useEffect(() => {
    dispatch({type : 'password', payload : password});
  }, [password]);

  return formValues;
}

// Now in your component -
const MyComponent = () => {
  const formValues = useLoginFormState(watch());
};

相关问题