刚刚又在鞭策Gemini 3干活,改造另外一个前端UI设计为卖点的产品,看能不能改造成我自己的产品,然后推广出去。
在Gemini 3干活的空袭,发现项目中使用Zustand作为状态管理,虽然我一直一把梭哈useState进行状态管理,有的时候也用Jotai,但是对于这些高级的状态管理工具,一直没有深入研究研究。
react中的状态
我们知道UI的渲染大致可以分为:状态 + 计算逻辑 + 渲染逻辑。而react中建议通过hooks把状态和计算逻辑统一管理,也就是useState之类的函数,从而实现与UI渲染的html,css逻辑分离。
有的时候,我们需要更加复杂的状态共享情况,比如在登录了之后,不同组件都需要因为登录状态的改变而改变。由于useState是局部状态,随着组件挂载/卸载而自生自灭,因此,我们需要进行状态提升:
- 提升到父组件:这样兄弟组件之间就能共享状态
- 提升到全局:通过useContext实现更广的,更全局的状态共享
但是这样又引入了性能问题:只要一个状态改变了,全部依赖的组件都需要重新渲染
所以,我们又需要进行细粒度的管理,在useState和useContext中写一堆判断逻辑,如果是组件中含有该状态,才进行更新,造成了不小的心智负担。
Zustand
既然全局状态管理非常有必要,但是细粒度的组件更新管理也需要设计,不如用Zustand组件吧。
Zustand是一个全局 + 集中式的状态管理工具,react全局共享一个巨大的useState(粗糙地可以这么理解),在react中就是这样:
// 假设这是一个“用户/设置”Store
const useUserStore = create(() => ({
userName: 'Alice',
theme: 'dark',
notifications: [],
// ...所有东西都在这里
}));
一个巨大的, 全局的store,状态和操作逻辑都被封装在了这里面
当某个小组件需要使用其中一个状态的时候,可以写:
const count = useKitchenStore(state => state.counter); // 我只要“计数器”这个食材
这样即使useKitchenStore中其他的状态发生了修改,也不会导致依赖counter这个状态的组件的重新渲染。
由于Zustand是一个巨大的,全局的store,其可能在大型的应用中比较好用,因为所有的状态都封装在一个对象中,观察所有的状态非常方便。
Jotai
同样也是一个全局状态管理的工具,不过是偏分布式的,不会有一个巨大的对象保存全部的状态,而是分散开为多个小对象(也依然是全局的)
最小的单元为Atom,封装着最小的状态和操作逻辑
// 独立的盒子 (Atom)
const counterAtom = atom(0);
const userNameAtom = atom('Alice');
const themeAtom = atom('dark');
当需要用某个UI组件需要用到某个状态的时候,内容如下:
const [count] = useAtom(counterAtom); // 我直接拿“计数器”这个盒子
由于状态本来就分散在不同的Atom中,因此这种模型的状态管理,天然组件渲染性能很好
总结
以后少用useContext和useState,直接梭哈Jotai或者Zustand,能少写一些通用代码逻辑就少写,早点完成早下班