使用 Hook useReducer 处理复杂状态的正确方法

Gen*_*ito 5 typescript reactjs react-hooks

试图赶上React Hooks。我读到他们建议useReducer在处理复杂的state. 但我的怀疑是从以下方案开始的:

使用React + Typescript,假设我有一个包含多个字段的状态(我将举例说明类):

type Person = {
   username: string,
   email: string
}

type Pet = {
   name: string,
   age: number
}

this.state: MyState = {
    person: Person,
    pet: Pet,
    loading: boolean
}
Run Code Online (Sandbox Code Playgroud)

如果我想用一种新的基于 Hooks 的方法来处理这种状态,我可以想到几个选项:

选项 1:useState为每个字段使用 Hook

const [person, setPerson] = useState<Person>(null)
const [pet, setPet] = useState<Pet>(null)
const [loading, setLoading] = useState<boolean>(false)
Run Code Online (Sandbox Code Playgroud)

这种方法的缺点是可扩展性低,我的一些真实状态至少有 15 个字段,难以管理。

选项 2:setState对整个对象使用单个

const [state, setState] = useState<MyState>({
    person: null,
    pet: null,
    loading: false
})
Run Code Online (Sandbox Code Playgroud)

这是对我来说似乎最简单的方法,我可以简单地执行setState((prev) => {...prev, person: {username: 'New', email: 'example@gmail.com'}})或调整它以适应任何现场修改。我什至可以一次更新多个字段。

选项3:使用useReducer通过使特定减速器为每一个,使用为每个复数场useState为简单的人

const [person, dispatchPerson] = useReducer<Person>(personReducer)
const [pet, dispatchPet] = useReducer<Pet>(petReducer)
const [loading, setLoading] = useState<boolean>(false)
Run Code Online (Sandbox Code Playgroud)

我发现这个是可以管理的,但我不认为必须用多行开关设置 reduce 函数的意义,除了在 Typescript 中为每个 reduce 函数设置调度类型的繁琐过程之外,当你可以时使用 setState 并完成它。

选项 4:useReducer对整个状态使用一个

const [state, dispatch] = useReducer(generalReducer)
Run Code Online (Sandbox Code Playgroud)

主要问题是reducer的类型,想想15个字段,其中所有类型和更新它们的信息结构都是不同的。在 Typescript 中指定类型无法缩放或不清楚。有几篇关于这个的文章,但没有一篇以干净的方式解决问题(示例 1),或者它们非常简单,不适用于问题(示例 2)。

处理此类案件的最佳方法是什么?状态中的字段数量很大并且可以具有多个深度级别。是否有代表这些案例的良好做法或任何官方示例?带有数字字段的示例用于处理博客作者或官方文档人员非常喜欢的简单计数器并没有太大帮助。

任何有关该主题的信息都将受到欢迎!提前致谢,对我的英语感到抱歉

gau*_*its 1

我们最近使用自定义钩子处理了类似的情况,因为减速器变得太不可预测了。想法是在自定义钩子中创建我们的状态,然后我们创建在状态上运行的类型安全帮助程序,然后我们公开状态和帮助程序。

interface State{
  count: number;
}

interface ExportType{
  state: State;
  add: (arg: number)=>void;
  subtract: (arg: number)=>void;
}

export default function useAddRemove(): ExportType {

    const [state, setState] = useState<State>({
        count: 0
    })
    
    function add(arg:number){
      setState(state=>({...state, count: state.count+arg}))
    }
    
    function subtract(arg:number){
      setState(state=>({...state, count: state.count-arg}))
    }


    return {
        state,
        add,
        subtract,
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您有任何建议,请告诉我。