突破Zustand的局限性:与React ContentAPI搭配使用

devtools/2024/11/27 19:47:42/

Zustand在状态管理中是非常适手的工具,在很多场景中我们都可以用它来解决复杂问题.

但是由于Zustand的设计理念,它仍然有一些限制,在这里用官网中的小demo举一个很简单的例子:

import { create } from 'zustand'
type CountStore = {count: numberinc: () => void
}
export const useCountStore = create<CountStore>((set) => ({count: 1,inc: () => set((state) => ({ count: state.count + 1 })),
}))

如上所示,我们在其他地方可以很灵活的使用count并且简易的控制inc函数count的值做修改。但是如果我们想要为此函数中的count设定灵活初始值的话,或者说是想要依靠React组件中传递来的一些值对其进行初始化的话,我们该怎么做呢?

事实上我们可以使用useEffect来对初值进行修改:

import { useCountStore } from "@/store/countStore"
type AppProps = {initialCount: number
}
export default function App ({initialCount}: AppProps) {count { count } = useCountStore()React.useEffect(() => {useCountStore.setState((prev) => ({...prev, count: initialCount}))}, [])return (<div>{ count }</div>)
}

在这个例子中,useEffect会在组件挂载后调用,并修改 store 中的count值。注意到初次渲染时,count会是初始值1,然后通过useEffect更新为传入的 initialCount。这种方式虽然可以解决问题,但它的缺点是需要两次渲染:第一次渲染时显示默认值,第二次渲染时显示传入的initialCount

这是遇到这个问题的很普遍或是说很简单的解决方法,不过很明显,它并不是一个很好的方法。

这样的处理逻辑是在组件中首先渲染了count的值为1,然后我们在useEffect中调用函数将count的值修改为我们所需的initialCount(更新我们所需的状态),然后组件会触发重新渲染,它在组件中将显示正确的值。这相当于我们用两次渲染来实现同样的事情,这在大型应用中是会极大的影响性能的


这篇文章中要强调的就是另外一种更为优雅的方式:

ZustandReactContextAPI结合使用

仍然是承接上文举一个小demo:

import React, { PropsWithChildren, useState } from "react";
import { StoreApi, createStore } from "zustand";
import { useStore } from "zustand/react";type CountStore = {count: number;inc: () => void;
};const CountContext = React.createContext<StoreApi<CountStore> | undefined>(undefined);type CountProviderProps = React.PropsWithChildren & {initialCount: number; // 设定初始值给 count
};export default function CountProvider({ children, initialCount }: CountProviderProps) {// 创建 store 对象const [store] = useState(() =>createStore<CountStore>((set) => ({count: initialCount, // 使用传入的 initialCount 作为初始值inc: () => set((state) => ({ count: state.count + 1 })),})));return <CountContext.Provider value={store}>{children}</CountContext.Provider>;
}export function useCountStore<T>(selector: (state: CountStore) => T) {const context = React.useContext(CountContext);if (!context) {throw new Error("CountContext.Provider is missing!");}return useStore(context, selector);
}

在上述代码中,在渲染时我们使用useState初始化了Zustandstore,使用传入的initialCount作为初始值。我们利用ContentAPI不会重新渲染的机制,确保在store状态发生改变的时候,CountProvider不会重新渲染,这样很有效的避免了性能上的问题,也解决了我们所谓初始store的“痛点”

最后我们可以按照如下方法进行初始化以及使用

import CountProvider, { useCountStore } from './CountProvider';function App() {return (<CountProvider initialCount={10}><ChildComponent /></CountProvider>);
}function ChildComponent() {const count = useCountStore((state) => state.count);return <div>Count: {count}</div>;
}

虽然通过React Context提供 store 是一种较好的方法,但它依然引入了一定的复杂性,尤其是在大规模应用中。如果有很多状态需要管理或者是组件数非常非常深的时候,不得不承认Context确实会带来一些额外的开销,这样我们就需要根据具体的场景制定特殊的方案或者使用其他相关工具来解决问题

总而言之言而总之,在我们需要状态管理的时候,还是要根据应用的复杂度和性能需求进行权衡,确保我们选取的工具较为合理

灵感来源:TkDodo’s blog / Zustand and React Context


http://www.ppmy.cn/devtools/137475.html

相关文章

YOLOv8实战木材缺陷识别

本文采用YOLOv8作为核心算法框架&#xff0c;结合PyQt5构建用户界面&#xff0c;使用Python3进行开发。YOLOv8以其高效的实时检测能力&#xff0c;在多个目标检测任务中展现出卓越性能。本研究针对木材缺陷数据集进行训练和优化&#xff0c;该数据集包含丰富的木材缺陷图像样本…

git如何给历史提交打标签

git如何给历史提交打标签 如果忘记给某个提交打标签&#xff0c;可以在之后补上 在项目所在文件夹&#xff0c;右键git bash here 查看历史标签&#xff1a; git tag创建标签&#xff1a; git tag -a 标签名号 commitSHA(历史提交校验码) -m 提交信息 git tag -a v1.0.0.…

pyhton+yaml+pytest+allure框架封装-全局变量渲染

我们在日常测试中 会有一个接口中多个值的情况 比如这种 { "name": "thread", "value": "4986-MainThread", "status": "framework", "start": "pytest", …

极狐GitLab 17.6 正式发布几十项与 DevSecOps 相关的功能【六】

GitLab 是一个全球知名的一体化 DevOps 平台&#xff0c;很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab 是 GitLab 在中国的发行版&#xff0c;专门为中国程序员服务。可以一键式部署极狐GitLab。 学习极狐GitLab 的相关资料&#xff1a; 极狐GitLab 官网极狐…

Failed to find SV in PRN block of SINEX file (Name svnav.dat)

gamit 精密星历生成失败 gamit svnav.dat没更新 下载svnav.dat.allgnss 重命名成 svnav.dat ,替换到tables&#xff0c;即可。

35 基于单片机的精确电压表DA-AD转换

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于51单片机&#xff0c;采用DAC0832和ADC0832检测电压&#xff0c;0到8.5V&#xff0c;设计复位电路 LED管显示实际稳压值&#xff0c;初始电压0 二、硬件资源 基于KEIL5编写C代码&#xff0c…

路由传参、搜索、多选框勾选、新增/编辑表单复用

前言&#xff1a; 记录添加运动员页面功能的具体实现 ①由赛事管理页面跳转时路由传参&#xff08;携带该页面表格中莫某条数据对应的赛事id到另一个页面&#xff09;&#xff1b; ②搜索框实时搜索&#xff1b; ③多选框勾选搜索&#xff1b; ④新增表单和编辑表单复用&a…

【Linux】Linux 内存管理机制

前言 Linux 的内存管理机制是一个复杂而高效的系统&#xff0c;旨在确保系统资源的高效利用&#xff0c;同时提供良好的性能和响应能力。本文主要介绍 Linux 内存管理的主要组件和机制。 虚拟内存 概念: 每个进程在 Linux 中拥有自己的虚拟地址空间&#xff0c;这使得进程之…