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

ops/2024/11/27 17:42:17/

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/ops/137128.html

相关文章

(计算机组成原理)期末复习

第一章 计算机的基本组成&#xff1a;硬件软件&#xff08;程序&#xff09;计算机系统 软件有系统软件&#xff08;系统管理工具&#xff09;&#xff0c;应用软件 计算机硬件&#xff1a;包括主机和外设&#xff0c;主机包括CPU和内存&#xff0c;***CPU由运算器和控制器所组…

计算机网络八股整理(一)

计算机网络八股文整理 一&#xff1a;网络模型 1&#xff1a;网络osi模型和tcp/ip模型分别介绍一下 osi模型是国际标准的网络模型&#xff0c;它由七层组成&#xff0c;从上到下分别是&#xff1a;应用层&#xff0c;表示层&#xff0c;会话层&#xff0c;传输层&#xff0c;…

简单的使用Ngrok使用https

1、ngrok 使用谷歌邮箱 https://dashboard.ngrok.com/ 2、使用ngrok docker化部署 最快 https://dashboard.ngrok.com/get-started/setup/docker 本地网络不行无法下载&#xff0c;使用其他工具下载 然后保存 docker save -o ngrok.tar ngrok/ngrok3、静态域名 docker ru…

代码随想录算法训练营day46|动态规划09

买卖股票的最佳时机四 之前是最多只能完成两笔交易&#xff0c;现在是至多可以买卖k次&#xff0c;那么状态数需要定为2*k1种&#xff0c;此时&#xff0c;就要分析多种情况的递推式 找到奇偶数交替的规则即可 class Solution { public:int maxProfit(int k, vector<int&g…

多边形拟合算法详解及代码解释

道格拉斯 - 普克算法&#xff08;Douglas-Peucker&#xff09; 原理&#xff1a; 首先在曲线的首尾两点 A&#xff0c; B之间连接一条直线AB &#xff0c;此直线作为曲线的弦4 。接着找到曲线上离该直线段距离最大的点 C&#xff0c;并计算其与 AB 的距离d 。然后将距离 d与…

网络安全审计机制与实现技术

目录 网络安全审计机制与实现技术网络安全审计机制与实现技术网络审计数据安全分析技术审计日志报表网络审计数据存储技术审计日志存储网络审计数据保护技术 网络安全审计机制与实现技术 技术分类&#xff1a;基于主机的审计机制、基于网络通信的审计机制、基于应用的审计机制…

Python设计模式详解之15 ——迭代器模式

Python 中的 Iterator&#xff08;迭代器&#xff09;设计模式 是一种行为型设计模式&#xff0c;用于逐一访问集合对象中的元素而不暴露其底层实现。Python 本身对迭代器模式提供了良好的支持&#xff0c;迭代器通常通过 __iter__ 和 __next__ 方法实现。 迭代器模式的组成 迭…

uniapp中使用uni-forms实现表单管理,验证表单

前言 uni-forms 是一个用于表单管理的组件。它提供了一种简化和统一的方式来处理表单数据&#xff0c;包括表单验证、字段绑定和提交逻辑等。使用 uni-forms可以方便地创建各种类型的表单&#xff0c;支持数据双向绑定&#xff0c;可以与其他组件及API进行良好的集成。开发者可…