首页  >  文章  >  web前端  >  Zustand,何时、如何以及为何

Zustand,何时、如何以及为何

PHPz
PHPz原创
2024-09-03 21:00:40657浏览

目录

  1. 状态管理简介
  2. 了解 Zustand
  3. 状态类型
  4. 开始使用 Zustand
  5. Zustand 的主要特点
  6. 实施 Zustand
  7. Zustand 与其他状态管理解决方案
  8. Zustand系统设计
  9. 使用 Zustand 保持状态
  10. 在 React 组件之外使用 Zustand
  11. 现实世界的例子
  12. 结论
  13. 提示:使用 Zustand 处理异步代码

1. 状态管理简介

状态管理是现代 Web 开发的一个重要方面,尤其是在复杂的应用程序中。它涉及处理可能随时间变化的数据,并确保该数据在整个应用程序中一致表示。有效的状态管理可以提高应用程序的可预测性和可维护性。

2. 了解 Zustand

Zustand 是一个小型、快速且可扩展的 React 应用程序状态管理解决方案。 Zustand 由 Jared Palmer 和 Daishi Kato 创建,提供了一个简单直观的 API,与其他解决方案相比,使状态管理变得不那么麻烦。

3. 国家类型

在深入了解 Zustand 之前,让我们先了解一下 Web 应用程序中不同类型的状态:

  1. 本地状态:特定于组件的状态,不需要与应用程序的其他部分共享。
  2. 全局状态:需要由应用程序中的多个组件访问和修改的状态。
  3. 远程状态:表示从外部源(通常是 API)获取数据的状态。

Zustand 擅长管理本地和全局状态,并且可以与远程状态管理解决方案集成。

4. Zustand 入门

要开始使用 Zustand,首先通过 npm、yarn 或 pnpm 安装它:

npm install zustand
# or
yarn add zustand
# or
pnpm add zustand

5. Zustand的主要特点

Zustand 具有多项使其脱颖而出的功能:

  1. 简单:Zustand 拥有最小的 API,使其易于学习和使用。
  2. 没有样板:与其他一些状态管理解决方案不同,Zustand 需要很少的设置代码。
  3. 基于 Hooks:Zustand 利用 React Hooks,使其感觉适合现代 React 开发。
  4. TypeScript 支持:Zustand 与 TypeScript 配合得很好,提供出色的类型推断。
  5. 中间件支持:Zustand 允许您通过中间件扩展其功能。
  6. Devtools 支持:Zustand 与 Redux DevTools 很好地集成以进行调试。
  7. 与框架无关:虽然主要与 React 一起使用,但 Zustand 可以在任何 JavaScript 环境中使用。

6. 实施 Zustand

让我们看一下 Zustand 的基本实现:

import { create } from 'zustand'

const useStore = create((set) => ({
  bears: 0,
  increasePopulation: () => set((state) => ({ bears: state.bears + 1 })),
  removeAllBears: () => set({ bears: 0 }),
}))

function BearCounter() {
  const bears = useStore((state) => state.bears)
  return <h1>{bears} around here...</h1>
}

function Controls() {
  const increasePopulation = useStore((state) => state.increasePopulation)
  return <button onClick={increasePopulation}>one up</button>
}

在此示例中,我们创建一个具有熊状态的商店和两个修改它的操作。然后,BearCounter 和 Controls 组件可以使用 useStore 钩子访问和修改状态。

7. Zustand 与其他状态管理解决方案

让我们将 Zustand 与其他流行的状态管理解决方案进行比较:

Zustand 与 Redux

Zustand 的优点:

  • 更简单的 API,更少的样板文件
  • 不需要动作创建者或 switch 语句
  • 较小的捆绑尺寸

缺点:

  • 尚未建立的生态系统
  • 更少的中间件选项

Zustand 与 MobX

Zustand 的优点:

  • 更简单、更少神奇的 API
  • 大型应用程序的更好性能

缺点:

  • 默认情况下反应性较低
  • 没有开箱即用的计算值

Zustand 与 Recoil

Zustand 的优点:

  • 更简单的心智模型
  • 在 React 之外工作

缺点:

  • 颗粒反应性较小
  • 没有内置原子族概念

八、Zustand系统设计

Zustand 的系统设计基于几个关键原则:

  1. Single store: Zustand encourages the use of a single store for all application state.
  2. Immutability: State updates are handled immutably, ensuring predictable behavior.
  3. Subscriptions: Components subscribe to specific parts of the state, re-rendering only when those parts change.
  4. Middleware: Zustand uses a middleware system for extending functionality.

This design allows Zustand to be both simple and powerful, providing excellent performance even in large applications.

9. Persisting State with Zustand

Zustand makes it easy to persist state, which is crucial for many applications. Here's an example using the persist middleware:

import { create } from 'zustand'
import { persist } from 'zustand/middleware'

const useStore = create(persist(
  (set, get) => ({
    fishes: 0,
    addAFish: () => set({ fishes: get().fishes + 1 }),
  }),
  {
    name: 'food-storage', // unique name
    getStorage: () => localStorage, // (optional) by default, 'localStorage' is used
  }
))

This will automatically save the state to localStorage and rehydrate it when the app reloads.

10. Using Zustand Outside React Components

One of Zustand's strengths is that it can be used outside of React components. This is particularly useful for integrating with other parts of your application or for testing:

const { getState, setState } = useStore

// Getting state
console.log(getState().bears)

// Setting state
setState({ bears: 10 })

// Using actions
getState().increasePopulation()

11. Real-World Examples

Let's look at some real-world examples of using Zustand:

Authentication State

import { create } from 'zustand'

const useAuthStore = create((set) => ({
  user: null,
  isAuthenticated: false,
  login: (userData) => set({ user: userData, isAuthenticated: true }),
  logout: () => set({ user: null, isAuthenticated: false }),
}))

// Usage in a component
function LoginButton() {
  const { isAuthenticated, login, logout } = useAuthStore()

  const handleAuth = () => {
    if (isAuthenticated) {
      logout()
    } else {
      // Simulate login
      login({ id: 1, name: 'John Doe' })
    }
  }

  return (
    <button onClick={handleAuth}>
      {isAuthenticated ? 'Logout' : 'Login'}
    </button>
  )
}

Shopping Cart

import { create } from 'zustand'

const useCartStore = create((set) => ({
  items: [],
  addItem: (item) => set((state) => ({ items: [...state.items, item] })),
  removeItem: (itemId) => set((state) => ({
    items: state.items.filter((item) => item.id !== itemId),
  })),
  clearCart: () => set({ items: [] }),
  total: 0,
  updateTotal: () => set((state) => ({
    total: state.items.reduce((sum, item) => sum + item.price, 0),
  })),
}))

// Usage in components
function CartSummary() {
  const { items, total, removeItem } = useCartStore()

  return (
    <div>
      {items.map((item) => (
        <div key={item.id}>
          {item.name} - ${item.price}
          <button onClick={() => removeItem(item.id)}>Remove</button>
        </div>
      ))}
      <div>Total: ${total}</div>
    </div>
  )
}

Theme Switcher

import { create } from 'zustand'
import { persist } from 'zustand/middleware'

const useThemeStore = create(persist(
  (set) => ({
    theme: 'light',
    toggleTheme: () => set((state) => ({
      theme: state.theme === 'light' ? 'dark' : 'light',
    })),
  }),
  {
    name: 'theme-storage',
  }
))

// Usage in a component
function ThemeToggle() {
  const { theme, toggleTheme } = useThemeStore()

  return (
    <button onClick={toggleTheme}>
      Switch to {theme === 'light' ? 'dark' : 'light'} mode
    </button>
  )
}

12. Conclusion

Zustand offers a refreshing approach to state management in React applications. Its simplicity, flexibility, and performance make it an excellent choice for both small and large projects. By reducing boilerplate and providing a straightforward API, Zustand allows developers to focus on building features rather than managing complex state logic.

While it may not have the extensive ecosystem of some older state management solutions, Zustand's design principles and ease of use make it a compelling option for modern React development. Its ability to work outside of React components and easy integration with persistence solutions further extend its utility.

For many React applications, Zustand strikes an excellent balance between simplicity and power, making it worth considering for your next project.

Bonus tips:

Zustand also handles asynchronous functions/code really well and without the need for any Middleware setup.

Let's talk a bit about that:

13. Handling Asynchronous Code with Zustand

One of Zustand's strengths is its simplicity in handling asynchronous operations without the need for additional middleware or complex setups. This makes it particularly easy to work with API calls, data fetching, and other asynchronous tasks.

How Zustand Handles Asynchronous Code

Zustand's approach to asynchronous code is straightforward:

  1. Direct Integration: Asynchronous functions can be defined directly in the store.
  2. No Special Syntax: You don't need to use special action creators or thunks.
  3. State Updates: You can update the state within async functions using the set function.
  4. Error Handling: Error states can be managed directly within the async functions.

Implementing Asynchronous Code

Here's an example of how to implement asynchronous code in Zustand:

import { create } from 'zustand'

const useUserStore = create((set) => ({
  user: null,
  isLoading: false,
  error: null,
  fetchUser: async (userId) => {
    set({ isLoading: true, error: null });
    try {
      const response = await fetch(`https://api.example.com/users/${userId}`);
      if (!response.ok) throw new Error('Failed to fetch user');
      const userData = await response.json();
      set({ user: userData, isLoading: false });
    } catch (error) {
      set({ error: error.message, isLoading: false });
    }
  },
}));

// Usage in a component
function UserProfile({ userId }) {
  const { user, isLoading, error, fetchUser } = useUserStore();

  React.useEffect(() => {
    fetchUser(userId);
  }, [userId]);

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error: {error}</div>;
  if (!user) return null;

  return (
    <div>
      <h1>{user.name}</h1>
      <p>Email: {user.email}</p>
    </div>
  );
}

In this example:

  1. We define an async fetchUser function directly in the store.
  2. The function manages loading and error states alongside the user data.
  3. We use the set function to update the state at different points in the async operation.
  4. In the component, we can use the store's state and actions as usual, with React hooks handling the component lifecycle.

Benefits of Zustand's Approach to Async Code

  1. Simplicity: No need for additional middleware or complex action creators.
  2. Flexibility: You can structure your async logic however you prefer.
  3. Readability: Async operations are defined close to the relevant state.
  4. Easy Testing: Async functions can be easily unit tested.

Comparison with Other Solutions

Unlike Redux, which often requires middleware like Redux Thunk or Redux Saga for handling async operations, Zustand's approach is much more straightforward. This simplicity can lead to less boilerplate and a gentler learning curve, especially for developers new to state management.

MobX and Recoil also offer ways to handle async operations, but Zustand's approach might be considered more intuitive due to its direct use of async/await syntax without additional abstractions.

异步的结论

Zustand 对异步代码的处理体现了其简单性和灵活性的理念。通过允许开发人员直接在存储中编写异步函数,无需特殊语法或中间件,Zustand 可以轻松管理复杂的状态操作,同时保持代码库干净和可读。

这种异步代码方法,与 Zustand 的其他功能(如小包大小和易于设置)相结合,使其成为各种规模的项目的绝佳选择,特别是那些涉及重要异步状态管理的项目。

希望这个“有点指南”对任何正在思考如何管理全局应用程序状态的人来说都是有用且富有洞察力的。
谢谢您,祝您编码愉快。

查看我的网站 https://www.ricardogesteves.com

跟着我@ricardogesteves
X(推特)

Zustand, When, how and why

RicardoGEsteves (里卡多·埃斯特维斯) · GitHub

全栈开发人员 |热衷于创造直观且有影响力的用户体验 |总部位于葡萄牙里斯本? - 里卡多·GE史蒂夫斯

Zustand, When, how and why github.com

以上是Zustand,何时、如何以及为何的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn