【问题标题】:How do you destructure a React useState hook into a namespace?你如何将 React useState hook 解构为命名空间?
【发布时间】:2019-06-16 21:48:20
【问题描述】:

作为个人喜好,我将 React 道具包装在命名空间中。它帮助我组织不同道具的来源。

使用useState 钩子我正在这样做。

function MyComponent() {
  const [todoCount, setTodoCount] = useState(100);
  const [doneCount, setDoneCount] = useState(0);
  const myState = {
    todoCount,
    setTodoCount,
    doneCount,
    setDoneCount
  };

  return (
    <>
      <Text>Todo {myState.todoCount}</Text>
      <Text>Done {myState.doneCount}</Text>
    </>
  );
}

状态设置有更简洁的语法吗?

我的失败尝试是

const myState = {
  [todoCount, setTodoCount]: useState(100),
  [doneCount, setDoneCount]: useState(0);
};

【问题讨论】:

  • 您至少可以省略 : count: setCount,但不确定它是否会比这更简洁
  • 你可以内联第二行,例如const myState = { count, setCount }...虽然我认为您的意思是一种在一行中同时进行的方式,自定义钩子? useNamespaceState(虽然 IMO 并没有真正在这里获得任何东西)
  • @CollinD 实际上我在第一部分中已经这样做了,但在第二部分中没有。应该复制/粘贴。 ???已编辑...谢谢。
  • 为什么不直接使用数组呢?或者至少可以创建自己的钩子,它将转换为对象?
  • @James 是的...我希望有一个衬里,这样我就可以启动 myState 命名空间内的所有状态。将示例更新为更复杂一点以显示此详细信息。

标签: javascript reactjs


【解决方案1】:

听起来像是custom hook 的一部分可以做的事情,例如

 function useMappedState(defaultState = {}) {
   const keys = Object.keys(defaultState);
   return keys.reduce((map, k) => {
     const fk = `set${k.charAt(0).toUpperCase()}${k.slice(1)}`;
     const [state, setState] = useState(defaultState[k]);
     map[k] = state;
     map[fk] = setState;
     return map;
   }, {});
 }
 ...
 const state = useMappedState({
   todoCount: 100,
   doneCount: 0
 });
 console.log(state.todoCount) // 100
 state.setTodoCount(5); // should set state of todoCount

theory 中,这应该会给你你想要的,但我没有测试过所以谨慎使用(例如,我什至不确定是否可以调用 hooks 可以调用在迭代器中)。 - 这个works fine

虽然,您所做的确实类似于 useReducer 已经做的,但可能值得尝试使用该钩子。

【讨论】:

  • 这很好用。谢谢你。 ? Typescript 和 ESLint 不喜欢它,但这正是我所要求的! ?
【解决方案2】:

当您需要管理复杂的状态时,useReducer 是首选。它是一个钩子,除了初始状态外,还接受减速器功能。 reducer 是由您编写的,用于将某些“动作”映射到状态变化。您可以根据您指定的规则将操作“调度”到 reducer 函数以更新状态。 useState 本身内部调用useReducer

/* action = { type: string, payload: any type } */

function reducer(state, { type, payload }) {
  switch(type) {
    case 'do-todo':
      return { doneCount: state.doneCount + 1, todoCount: state.todoCount - 1 }
    case 'undo-todo':
      return { doneCount: state.doneCount - 1, todoCount: state.todoCount + 1 }
    default:
      return state
  }
}

function App() {
  const [ state, dispatch ] = useReducer(reducer, { todoCount: 100, doneCount: 0 }) 

  return (
    <>
      <Text>Todo {state.todoCount}</Text>
      <Text>Done {state.doneCount}</Text>
      <Button onClick={() => dispatch({ type: 'do-todo' })}>Do Todo</Button>
    </>
  );
}

您可以使用多个 reducer 映射到多个命名空间。

【讨论】:

    猜你喜欢
    • 2010-09-19
    • 2021-06-15
    • 2021-06-30
    • 2010-09-12
    • 1970-01-01
    • 2021-07-29
    • 1970-01-01
    • 2010-12-27
    • 2021-12-02
    相关资源
    最近更新 更多