回忆一下,我们在使用
Zustand
时,是这样引入状态的(如下),通过解构的方式引入状态,但是这样引入会引发一个问题!
1.对象解构
比如说:
- A组件用到了
hobby.rap
状态,而B组件 没有用到hobby.rap
状态。- 但是更新
hobby.rap
这个状态的时候,A组件和B组件都会重新渲染。- 这样就导致了不必要的重渲染,因为B组件并没有用到
hobby.basketball
这个状态。
缺点:
- 重复渲染,如果
useUserStore
中定义得其他state
状态值改变。 - 当前组件并没有用到其他
state
状态, 也是会触发渲染,产生性能问题! - 我们可以通过, 状态选择器、useShallow 来解决上面所说问题!
// A组件
import useUserStore from '../store/user'
const { hobby, name } = useUserStore()
return (
<div className="left">
<h1>A组件</h1>
<div>
<h3>{name}</h3>
<div>{hobby.rap}</div>
</div>
</div>
)
// B组件
const { name } = useUserStore()
return (
<div className="left">
<h1>B组件</h1>
<div>
<h3>{name}</h3>
</div>
</div>
)
2.状态选择器
- 所以为了规避这个问题,我们可以使用状态选择器,状态选择器可以让我们只选择我们需要的部分状态,这样就不会引发不必要的重渲染。
- 缺点:用到一个属性就需要手动定义一个,很麻烦、易出错。
import useUserStore from '../store/user'
const name = useUserStore((state) => state.name)
const rap = useUserStore((state) => state.hobby.rap)
3.useShallow
Zustand 默认情况是它会严格比较两个对象是否相等, 没更新属性一次都会重新渲染!
包裹 useShallow 之后,虽然返回的是一个新的对象,但是不会去对比两个新对象的引用地址;
而是对比里面的属性是否发生变化,若是属性发生变化就会重新渲染;
如果属性中没有包含 name, 它就不会去对比,也不会去更新!从而避免更新问题;
import { useShallow } from 'zustand/react/shallow';
const { rap } = useUserStore(useShallow((state) => ({
rap: state.hobby.rap,
})))
4.总结
使用 useShallow
hooks 简化状态才是最优解。