【问题标题】:confused by UseReducer被 UseReducer 弄糊涂了
【发布时间】:2022-01-23 07:56:25
【问题描述】:

大家好,我想知道是否有人可以帮助我理解 useReducer。这是有人向我建议的,因为我正在使用一个包含大量输入的表单,我想动态地访问应用程序的其他区域。我是新来的反应,我正在努力让它按我的意愿工作。这是我目前正在使用的内容。

    const Form= () => {
const useReducerState = (initialState = {
    
}) => {    
    const reducer = (prev, next) => ({ ...prev, ...next });
    return useReducer(reducer, initialState);
};

const [state, setState] = useReducerState({
input1: "",
input2: "",
input 3: "",
input 4: "",
input 6: "",
input 7: "",
input 8: "",
input 9: "",
 });


 const handleChange = (e) => {        
    let proToUpdate = e.target.name;
    let value = e.target.value;
    setState({ [proToUpdate]: value });    
     }

const {
    input 1,
    input 2,
    input 3,
    input 4,
    input 5, 
    input 6,
    input 7,
    input 8,
    input 9
    
} = state;



return ( jsx form with inputs matching the state above ) } 

我遵循的指南似乎与其他指南的格式不同。由于我真的不明白发生了什么,我无法将表单重置为默认值,这似乎是减速器的要点。教我尝试作弊,我猜只是抄别人的作业:)

【问题讨论】:

  • 更准确地说,为什么初始状态在 const{} 的底部,而不是在 initialState = {} 的顶部。

标签: reactjs use-reducer


【解决方案1】:

您的帖子清楚地反映出对 React 和 hooks 的工作原理缺乏了解。在遵循互联网上任何令人困惑的指南之前,请阅读official documentation。官方文档不会出错,因为它首先展示了它的用途。

首先,要使您的代码正常工作,您必须将useReducerState 移出组件。为什么?每次渲染组件时,useReducerState 将是一个新函数。你的函数是一个钩子,你最好将它移动到它自己的文件中并导出它。

其次,如果您了解 Redux,请将 useReducer 视为组件的本地存储。 useReducer 的第一个参数是一个reducer,reducer 是一个纯函数,将状态作为第一个参数,action 作为第二个参数并返回一个新的状态。所以,我根本不明白这一行:

const reducer = (prev, next) => ({ ...prev, ...next });

“next”应该是一个动作,它是一个具有两个属性的对象:type(被调度的动作的类型)和payload(嗯,有效载荷) .

这一行更令人困惑:

const [state, setState] = useReducerState({

useReducer 的签名是这样的:

const [state, dispatch] = useReducer(reducer, initialArg, init);

所以你是怎么得到setState的对我来说是个谜。

最后,我没有在你的组件中看到任何调度(?)为什么要使用 useReducer 呢?从您的代码来看,您似乎想使用useState,它确实在数组中返回了一个 setState。

由于我不太明白发生了什么,我无法将表单重置为默认值,这似乎是 reducer 的重点。

不清楚你在这里的意思,但 reducer 的重点是调度一个动作,该动作将指示你的状态发生什么变化并返回新的状态。使用useReducer,您不必这样做:

setState(prevState => ({
  ...prevState,
  [proPToUpdate]: value
}))

官方文档摘录:

const initialState = {count: 0};

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return {count: state.count + 1};
    case 'decrement':
      return {count: state.count - 1};
    default:
      throw new Error();
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({type: 'decrement'})}>-</button>
      <button onClick={() => dispatch({type: 'increment'})}>+</button>
    </>
  );
}

在你的情况下,大致如下:

const initialState = {
input1: "",
input2: "",
input 3: "",
input 4: "",
input 6: "",
input 7: "",
input 8: "",
input 9: "",
 }

function reducer(state, action) {
  switch (action.type) {
    case 'setInput1':
      return { ...state, input1: action.payload};
    case 'setInput2':
      return { ...state, input2: action.payload};
    case 'reset':
      return initialState;
    default:
      throw new Error();
  }
}


...
const [state, dispatch] = useReducer(reducer, initialState)
...
dispatch({ type: 'reset' });
dispatch({ type: 'setInput1', payload: value });


更多。是的,这段代码

const reducer = (prev, next) => ({ ...prev, ...next });
return useReducer(reducer, initialState);

确实有效,但您失去了可读性。让我们直言不讳。使用减速器时,您必须向它传递一个动作。一个动作必须有一个类型。上面的代码有效,但它是错误的。它正在转移useReducer 的合法用途,以获取什么?更少的代码?是的,但绝不会以牺牲可读性和语义为代价。当您打算使用.forEach 时,这与使用.map 而不是.forEach 相同。

如果我在某处看到这个(由其他人写的):

setState({ [proToUpdate]: value });

你觉得我会怎么做?我会说,嘿,你的代码错了,应该是

setState(prevState => ({ ...prevState, [proToUpdate]: value }));

并修复它。不知道有一个 useReducer 在幕后发挥作用......这是错误的。

我见过很多人为了讨价还价几行代码而做一些奇怪的事情,而且这并不总是很漂亮,通常来自互联网上的指南、Medium 等!不要忘记,您可能并不孤单地处理此代码。让它对每个人都可读,更重要的是,使其有意义。

【讨论】:

  • 谢谢你。是的,我查看了所有文档。我去youtube的原因是所有解释都坚持以计数器为例。我有多个要管理的状态值,所有示例都只使用一个 {counter},这意味着很难理解如何在实际案例中扩展它。
  • 我明白了。要我添加一个例子吗?
  • 如果可以,那就太好了。似乎缺乏处理多个状态值的解释。我使用了 reducer,因为我有很多输入。计划是有一个函数可以有效地设置每个值的状态,允许我在需要时将所有值重置为默认值。所有示例都使用一个值和两种类型的计数器,递减和递增,这令人困惑。我发现的版本的奇怪之处在于它有效。它从输入中获取值并更新状态。从你所说的来看,它只是以一种奇怪的方式完成。 :)
  • 我编辑了我的答案:)
  • 现在我更加困惑了。如果您现在必须为每个输入做一个 switch 语句,那有什么意义。为每个 SetState 做一个 switch 语句会更容易。
猜你喜欢
  • 2019-01-12
  • 1970-01-01
  • 2014-08-14
  • 2016-02-16
  • 1970-01-01
  • 1970-01-01
  • 2017-07-24
  • 2011-08-02
  • 1970-01-01
相关资源
最近更新 更多