zustand让你的React应用更简洁高效

大家好,我是白露。

今天我想和大家分享一个我最近在React项目中频繁使用的状态管理库 —— zustand。简单来说,zustand是一个轻量级的状态管理解决方案,它可以让你的React应用状态管理变得异常简单和高效。

最近几个月我一直在使用zustand,发现它不仅解决了我在React状态管理中遇到的许多痛点,还大大提高了我的开发效率。我相信,这个库也能帮助到许多和我有同样困扰的React开发者们。

1. 为什么需要zustand?

作为一个热爱React的程序员,我一直在寻找能够简化状态管理的方法。

在我的日常开发中,经常需要处理复杂的应用状态。使用React的Context API和useState hook可以解决一些简单的状态管理需求,但在大型应用中,它们往往显得力不从心。另一方面,Redux虽然强大,但有时候会感觉太重了,特别是对于中小型项目来说。

正是在这样的背景下,我开始寻找一个轻量级但功能强大的状态管理解决方案。在尝试了多个库之后,我最终选择了zustand。它不仅简单易用,还保持了良好的性能和灵活性。

2. zustand是什么?

zustand是一个小型、快速和可扩展的状态管理解决方案。使用zustand的主要优势包括:

  1. 简单: API非常简洁,学习曲线平缓。
  2. 轻量级: 体积小,不到1KB(压缩后)。
  3. 灵活: 可以轻松集成到任何React应用中,不需要Provider。
  4. 高性能: 采用基于发布订阅的模型,确保高效的更新。
  5. TypeScript友好: 提供了出色的TypeScript支持。

3. 如何使用zustand?

让我们通过一些实际的例子来看看如何使用zustand。

3.1 基本用法

首先,让我们创建一个简单的计数器store:

  1. import create from 'zustand'
  2. const useStore = create((set) => ({
  3. count: 0,
  4. increment: () => set((state) => ({ count: state.count + 1 })),
  5. decrement: () => set((state) => ({ count: state.count - 1 })),
  6. }))

然后,在React组件中使用这个store:

  1. import React from 'react'
  2. import useStore from './store'
  3. function Counter() {
  4. const { count, increment, decrement } = useStore()
  5. return (
  6. <div>
  7. <h1>{count}</h1>
  8. <button onClick={increment}>+1</button>
  9. <button onClick={decrement}>-1</button>
  10. </div>
  11. )
  12. }

就是这么简单!

无需Provider,无需复杂的设置,我们就创建了一个功能完整的计数器应用。

3.2 异步操作

zustand也可以轻松处理异步操作。让我们创建一个加载用户数据的store:

  1. import create from 'zustand'
  2. const useStore = create((set) => ({
  3. user: null,
  4. loading: false,
  5. error: null,
  6. fetchUser: async (id) => {
  7. set({ loading: true })
  8. try {
  9. const response = await fetch(`https://api.example.com/users/${id}`)
  10. const user = await response.json()
  11. set({ user, loading: false, error: null })
  12. } catch (error) {
  13. set({ error, loading: false })
  14. }
  15. }
  16. }))

在组件中使用:

  1. function UserProfile({ id }) {
  2. const { user, loading, error, fetchUser } = useStore()
  3. React.useEffect(() => {
  4. fetchUser(id)
  5. }, [id])
  6. if (loading) return <div>Loading...</div>
  7. if (error) return <div>Error: {error.message}</div>
  8. if (!user) return null
  9. return <div>{user.name}</div>
  10. }

4. zustand的高级用法

zustand不仅可以处理基本的状态管理,还可以应对更复杂的场景。

4.1 中间件

zustand支持中间件,让你可以扩展store的功能。例如,我们可以添加一个logger中间件:

  1. import create from 'zustand'
  2. const log = (config) => (set, get, api) =>
  3. config(
  4. (...args) => {
  5. console.log(' applying', args)
  6. set(...args)
  7. console.log(' new state', get())
  8. },
  9. get,
  10. api
  11. )
  12. const useStore = create(
  13. log((set) => ({
  14. bears: 0,
  15. increasePopulation: () => set((state) => ({ bears: state.bears + 1 })),
  16. }))
  17. )

4.2 持久化

zustand可以轻松实现状态的持久化,例如保存到localStorage:

  1. import create from 'zustand'
  2. import { persist } from 'zustand/middleware'
  3. const useStore = create(
  4. persist(
  5. (set) => ({
  6. fishes: 0,
  7. addFish: () => set((state) => ({ fishes: state.fishes + 1 })),
  8. }),
  9. {
  10. name: 'food-storage', // unique name
  11. getStorage: () => localStorage, // (optional) by default, 'localStorage' is used
  12. }
  13. )
  14. )

5. zustand与React Hooks的集成

zustand设计的一个亮点是它与React Hooks的无缝集成。

你可以在任何函数组件中使用zustand创建的store,就像使用普通的React Hook一样。

例如,我们可以创建一个自定义hook来封装特定的状态逻辑:

  1. import create from 'zustand'
  2. const useStore = create((set) => ({
  3. todos: [],
  4. addTodo: (text) => set((state) => ({
  5. todos: [...state.todos, { id: Date.now(), text, completed: false }]
  6. })),
  7. toggleTodo: (id) => set((state) => ({
  8. todos: state.todos.map(
  9. todo => todo.id === id ? { ...todo, completed: !todo.completed } : todo
  10. )
  11. })),
  12. }))
  13. // 自定义hook
  14. function useTodos() {
  15. const todos = useStore((state) => state.todos)
  16. const incompleteTodos = todos.filter(todo => !todo.completed)
  17. return { todos, incompleteTodos }
  18. }
  19. // 在组件中使用
  20. function TodoList() {
  21. const { todos, incompleteTodos } = useTodos()
  22. const addTodo = useStore((state) => state.addTodo)
  23. const toggleTodo = useStore((state) => state.toggleTodo)
  24. // 组件逻辑...
  25. }

这种方式让我们可以更好地组织和复用状态逻辑,同时保持组件的简洁。

6. zustand vs Redux

作为React生态系统中最流行的状态管理库,Redux自然会成为我们比较的对象。那么,zustand相比Redux有哪些优势呢?

  1. 简单性: zustand的API更加简洁,学习曲线更平缓。Redux需要理解actions, reducers, middleware等概念,而zustand只需要理解store和update函数。
  2. 样板代码: zustand几乎没有样板代码,而Redux通常需要编写大量的样板代码。
  3. 性能: zustand采用基于发布订阅的模型,在某些场景下可能比Redux的全局状态树更高效。
  4. 灵活性: zustand不需要像Redux那样将整个应用包裹在Provider中,可以更灵活地在应用的不同部分使用。
  5. TypeScript支持: 虽然Redux也支持TypeScript,但zustand的TypeScript支持更加直观和简单。

选择zustand Or Redux,这取决于你~

7. zustand的性能优化

尽管zustand已经在性能方面做了很多优化,但在使用时仍然需要注意一些问题以确保最佳性能。

  1. 选择性订阅: 只订阅组件需要的状态,避免不必要的重渲染。
  1. // 好的做法
  2. const bears = useStore(state => state.bears)
  3. // 避免这样做
  4. const { bears } = useStore()
  1. 使用selector函数: 对于复杂的状态计算,使用selector函数可以避免不必要的重计算。
  1. const totalBears = useStore(state => state.bears.reduce((sum, bear) => sum + bear.count, 0))
  1. 批量更新: 如果需要同时更新多个状态,可以在一个函数中完成以减少重渲染次数。
  1. const updateAll = useStore(state => state.updateAll)
  2. updateAll({ bears: 10, fishes: 20, trees: 30 })
  1. 使用shallow比较: 对于对象或数组类型的状态,可以使用shallow比较来避免不必要的重渲染。
  1. import { shallow } from 'zustand/shallow'
  2. const { bears, fishes } = useStore(
  3. state => ({ bears: state.bears, fishes: state.fishes }),
  4. shallow
  5. )

8. zustand的生态系统

虽然zustand本身非常轻量,但它也有一个不断增长的生态系统。以下是一些值得关注的zustand相关项目:

  1. zustand-middleware-xstate: 将XState与zustand集成,用于复杂的状态管理场景。
  2. zustand-middleware-yjs: 用于实现协同编辑功能的中间件。
  3. zustand-forms: 基于zustand的表单状态管理解决方案。
  4. zustand-persist: 用于状态持久化的中间件。
  5. zustand-computed: 为zustand添加计算属性支持。

这些项目进一步扩展了zustand的功能,使其能够应对更多复杂的状态管理场景。Github上还有很多,欢迎大家补充~

结论

zustand是一个强大而灵活的状态管理库,它可以帮助你更高效地管理React应用的状态。从简单的计数器到复杂的异步操作,从基本的状态更新到高级的中间件使用,zustand都能轻松应对。

通过使用zustand,你可以:

  1. 减少样板代码
  2. 提高代码的可读性和可维护性
  3. 更灵活地管理应用状态
  4. 优化应用性能

开始使用zustand吧,让你的React状态管理变得更简单、更强大!

延伸阅读

  1. zustand官方文档
  2. zustand最佳实践

写了这么多,大家不点赞或者star一下,说不过去了吧?

项目地址: https://github.com/pmndrs/zustand