Zustand 第三章(状态简化)

状态简化

回忆一下我们在使用zustand时,是这样引入状态的(如下),通过解构的方式引入状态,但是这样引入会引发一个问题,例如A组件用到了 hobby.basketball 状态,而B组件 没有用到 hobby.basketball 状态,但是更新hobby.basketball这个状态的时候,A组件和B组件都会重新渲染,这样就导致了不必要的重渲染,因为B组件并没有用到hobby.basketball这个状态。

tsx 复制代码
const { name, age, hobby, setHobbyRap, setHobbyBasketball } = useUserStore()
return (
    <div className="left">
        <h1>A组件</h1>
        <div>
            <h3>{name}</h3>
            <div>年龄:<span>{age}</span></div>
            <div>爱好1:<span>{hobby.sing}</span></div>
            <div>爱好2:<span>{hobby.dance}</span></div>
            <div>爱好3:<span>{hobby.rap}</span></div>
            <div>爱好4:<span>{hobby.basketball}</span></div>
            <button onClick={() => setHobbyRap('只因你太美')}>改变爱好rap</button>
            <button onClick={() => setHobbyBasketball('篮球')}>改变爱好basketball</button>
        </div>
    </div>
)

状态选择器

所以为了规避这个问题,我们可以使用状态选择器,状态选择器可以让我们只选择我们需要的部分状态,这样就不会引发不必要的重渲染。

tsx 复制代码
const name = useUserStore((state) => state.name)
const age = useUserStore((state) => state.age)
const rap = useUserStore((state) => state.hobby.rap)
const basketball = useUserStore((state) => state.hobby.basketball)

useShallow

你以为这样就结束了? 并没有,你可以想一下如果一个属性很多,例如100个,那我们写起来岂不是要疯了,但是你用解构的话他又会造成不必要的重渲染,真是生与死轮回不止,这时候我们就可以使用useShallow来避免这个问题。

useShallow 只检查顶层对象的引用是否变化,如果顶层对象的引用没有变化(即使其内部属性或子对象发生了变化,但这些变化不影响顶层对象的引用),使用 useShallow 的组件将不会重新渲染

tsx 复制代码
import { useShallow } from 'zustand/react/shallow';
const { rap, name } = useUserStore(useShallow((state) => ({
    rap: state.hobby.rap,
    name: state.name
})))

代码获取

store/user.ts

ts 复制代码
import { create } from 'zustand'
import { immer } from 'zustand/middleware/immer'
interface User {
    name: string,
    age: number,
    hobby: {
        sing: string,
        dance: string,
        rap: string,
        basketball: string,
    }
    setHobbyRap: (rap: string) => void,
    setHobbyBasketball: (basketball: string) => void
}
const useUserStore = create<User>()(immer((set) => ({
    name: '坤坤',
    age: 18,
    hobby: {
        sing: '坤式唱腔',
        dance: '坤式舞步',
        rap: '坤式rap',
        basketball: '坤式篮球'
    },
    setHobbyRap: (rap: string) =>set((state) => {
        state.hobby.rap = rap
    }),
    setHobbyBasketball: (basketball: string) => set((state) => {
        state.hobby.basketball = basketball
    })
})))

export default useUserStore;

A component

tsx 复制代码
import '../index.css'
import useUserStore from '../../store/user';
export default function Left() {
    console.log('A组件渲染')
    const { name, age, hobby, setHobbyRap, setHobbyBasketball } = useUserStore()
    return (
        <div className="left">
            <h1>A组件</h1>
            <div>
                <h3>{name}</h3>
                <div>年龄:<span>{age}</span></div>
                <div>爱好1:<span>{hobby.sing}</span></div>
                <div>爱好2:<span>{hobby.dance}</span></div>
                <div>爱好3:<span>{hobby.rap}</span></div>
                <div>爱好4:<span>{hobby.basketball}</span></div>
                <button onClick={() => setHobbyRap('只因你太美')}>改变爱好rap</button>
                <button onClick={() => setHobbyBasketball('篮球')}>改变爱好basketball</button>
            </div>
        </div>
    )
}

B component

tsx 复制代码
import '../index.css'
import useUserStore from '../../store/user';
import { useShallow } from 'zustand/react/shallow';
export default function Right() {
    console.log('B组件渲染')
    const { rap, name } = useUserStore(useShallow((state) => ({
        rap: state.hobby.rap,
        name: state.name
    })))
    return (
        <div className="right">
            <h1>B组件</h1>
            <div>
                <div>姓名:<span>{name}</span></div>
                <div>rap:<span>{rap}</span></div>
            </div>
        </div>
    )
}

css

css 复制代码
.left {
    width: 50%;
    height: 100%;
    border: 1px solid rgb(19, 204, 148);
    height: 300px;
    margin:30px;
    padding: 20px;
    border-radius: 10px;
}


.right {
    width: 50%;
    height: 100%;
    border: 1px solid rgb(214, 35, 35);
    height: 300px;
    margin:30px;
    padding: 20px;
    border-radius: 10px;
}


.left button {
    margin: 10px;
    padding: 10px;
}

.right button {
    margin: 10px;
    padding: 10px;
}
相关推荐
_揽12 分钟前
html如何在一张图片上的某一个区域做到点击事件
前端·html
踢足球的,程序猿15 分钟前
从 Vue 2.0 进阶到 Vue 3.0 的核心技术解析指南
前端·javascript·vue.js·前端框架·html
冷凌爱17 分钟前
Fetch与Axios:区别、联系、优缺点及使用差异
前端·node.js·js
袁煦丞38 分钟前
跨平台终端王者Tabby:cpolar内网穿透实验室第632个成功挑战
前端·程序员·远程工作
Sailing40 分钟前
Grafana-mcp-analyzer:基于 MCP 的轻量 AI 分析监控图表的运维神器!
前端·node.js·mcp
阿山同学.1 小时前
AWS 亚马逊 S3存储桶直传 前端demo 复制即可使用
前端·javascript·aws
Jolyne_1 小时前
grid 实现完美的水平铺满、间隔一致的自适应布局
前端·css
西洼工作室1 小时前
【解决导航栏字体图标渲染导致文本闪烁问题】采用腾讯视频的解决方案
前端·css·css3
WindrunnerMax1 小时前
从零实现富文本编辑器#5-编辑器选区模型的状态结构表达
前端·架构·github
CodeSheep1 小时前
宇树科技,改名了!
前端·后端·程序员