创建和使用Store

Zustand依旧采用了Flux的单向数据流的概念,也采用了其中所设计的结构。所以在使用Zustand的时候并不需要特别的去学习新内容,我们所要关心的只有Store和Action。在Zustand中,Store的组织是以Hook的形式出现的,所以定义一个Store,实际上就是创建了一个Hook。

这里我们依旧采用之前在MobX中使用过的实例。

import create from 'zustand';

const useGearBox = create(set => ({
  currentGear: 0,
  ecoMode: false,
  sportMode: false,
  shiftUp: () => set(state => ({ currentGear: state.currentGear + 1 })),
  shiftDown: () => set(state => ({ currentGear: state.currentGear - 1 })),
  switchEcoMode: () => set(state => ({ ecoMode: !state.ecoMode })),
  switchSportMode: () => set(state => ({ sportMode: !state.sportMode }))
}));

在上面这个示例中,创建了一个只携带有一个State和两个Action的Store。这里有两个内容需要额外说明一下。Zustand的Store中,需要使用create函数提供的参数set来执行State的合并。在没有执行set的时候,State是不会发生改变的。我们不需要在调用set的时候更改整个的State,只需要列出需要发生更改的部分即可,Zustand会将更改和原有的State进行合并。

定义Store中要持有的State就更加简单了,只需要将所需要使用的State列出来,赋上默认值即可。在Zustand的Store中,你可以使用任意类型的和任意复杂度的内容来作为State。因为在默认条件下,Zustand都是以绝对相等(===)的比较来判定对象是否发生了变化的,所以即便是使用了比较复杂的数据结构,依旧不会影响Zustand对于数据是否发生变化的响应。

在Zustand中,Action的定义也是比较简单的,从上面的示例中可以看出来,Zustand中的Action实际上就是一个普通的实例方法。Zustand没有像Redux和MobX那样对Action提出多少定义形式和内容上的要求,你可以根据实际的需要定义符合你的需求的Action。

定义好的Store在React组件中的使用就更简单了,只需要使用定义好的Store Hook从定义的Store中选出所要使用的部分即可。例如以下示例。

export const GearDisplay = () => {
  const gear = useGearBox(state => state.currentGear);

  return <div>Current Gear: {gear}</div>;
};

export const GearOperator = () => {
  const shiftUp = useGearBox(state => state.shiftUp);
  const shiftDown = useGearBox(state => state.shiftDown);

  return (
    <div>
      <button onClick={shiftUp}>Shift Up</button>
      <buton onClick={shiftDown}>Shift Down</buton>
    </div>
  );
};

在上面这个实例中定义了两个组件,其中第一个组件从Store中选取了Store持有的一个State,并将其渲染到了页面上。在这种情况下,如果Zustand中持有的State发生了变化,Zustand就会使组件重新渲染。

在另一个组件中则是直接选择了Store中的两个Action。这里可以看到,在组件中选取Action的操作跟选取State的操作是一样的。从Store中选取出来的Action可以直接在组件中调用执行,也可以直接将其赋予组件上的事件,Zustand对于这一点依旧没有给定任何限制。