为什么我不在 React 中使用状态管理库
为什么我不再使用 React 状态管理库
https://medium.com/@ipla/why-i-no-longer-use-a-react-state-management-library-7bdffae54600
指数
几年前,当我刚开始学习 React 时,要想成为一名 React 开发人员,你需要了解**两件事**:**TypeScript 和 Redux**。
如今,情况已经改变。如果您刚刚学习 React 并遇到状态管理的概念,您会对众多的库感到不知所措:Redux、Redux Toolkit、MobX、Jotai、Zustand,等等。
但在深入探讨之前,让我们先回答一个基本问题:
什么是全局状态管理库?
即使你对 React 还比较陌生,你可能也知道术语 **state** 的含义。您使用 `useState` 钩子创建一个,当您更新它时,您的应用程序会重新渲染以反映更改。
然而,当你需要在 React 应用程序的多个不相连的部分之间共享一些信息时,事情就会变得复杂。
这就是我们常说的**全局状态**,也是状态管理库试图解决的问题:**如何让任何组件都能访问共享状态**。
让我们看看 Redux Toolkit 如何处理这个问题。
Redux 工具包如何解决全局状态
首先,创建一个**商店**:
import { configureStore } from '@reduxjs/toolkit'; export const store = configureStore({ reducer: {}, }); // Inferindo os tipos de RootState e AppDispatch usando a store export type RootState = ReturnType; export type AppDispatch = typeof store.dispatch;
这是您的全局状态存在的**中心位置**。然后使用 **provider** 包装您的应用程序,使所有组件都可以访问它:
import React from 'react'; import ReactDOM from 'react-dom'; import { Provider } from 'react-redux'; import App from './App'; import { store } from './app/store'; ReactDOM.render(, document.getElementById('root') );
现在,您需要定义**切片**,它们是全局状态的各个部分。例如:
import { createSlice } from '@reduxjs/toolkit'; interface CounterState { value: number; } const initialState: CounterState = { value: 0 }; export const counterSlice = createSlice({ name: 'counter', initialState, reducers: { increment: (state) => { state.value += 1; }, decrement: (state) => { state.value -= 1; }, incrementByAmount: (state, action) => { state.value += action.payload; }, }, }); export const { increment, decrement, incrementByAmount } = counterSlice.actions; export default counterSlice.reducer;
最后,连接这个:
import { configureStore } from '@reduxjs/toolkit'; import counterReducer from './features/counter/counterSlice'; export const store = configureStore({ reducer: { counter: counterReducer }, });
此时,您可以在组件中使用全局状态,如下所示:
import React from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { increment, decrement } from './counterSlice'; export function Counter() { const count = useSelector((state) => state.counter.value); const dispatch = useDispatch(); return ({count}); }
虽然 Redux Toolkit 大大简化了 Redux,但它仍然包含**大量针对通常简单需求的样板代码**。我们甚至还没有讨论像服务器请求这样的异步操作!
此外,许多初学者都陷入了将所有状态都放在 Redux 中的陷阱,导致全局存储臃肿且更难管理。
全球国家的两面性
仔细想想,大多数“全球状态”可以分为两类:
让我们分别讨论一下每一个问题。
精益的全球状态方法
使用现代工具,您无需专门的状态管理库即可处理全局状态:
**1.要获取服务器状态,请使用 TanStack 查询**
TanStack Query(以前称为 React Query)专门用于管理服务器状态。它可以处理缓存、重新加载、陈旧数据等,所有这些都是开箱即用的,您绝对应该使用它,因为您真的不想从头开始重新实现所有这些。例如,搜索客户列表非常简单:
import { useQuery } from '@tanstack/react-query'; function Customers() { const { data, error, isLoading } = useQuery(['customers'], fetchCustomers); if (isLoading) returnLoading...; if (error) returnError: {error.message}; return
- {data.map((customer) =>
- {customer.name} )}
TanStack Query 消除了手动管理服务器状态的需要,并且由于您获取的状态已被缓存,您可以在所有组件中以完全相同的方式使用它,并且只会被获取一次。
**2.对于共享状态使用 Observables**
对于较小的、特定于应用程序的状态(例如用户登录),我使用 **Observable** 模式的轻量级实现:
export class Observable{ private _value: T; private subscribers = new Set<(value: T) => void>(); constructor(initialValue: T) { this._value = initialValue; } get value() { return this._value; } set value(newValue: T) { this._value = newValue; this.notify(); } subscribe(callback: (value: T) => void) { this.subscribers.add(callback); callback(this._value); return { unsubscribe: () => this.subscribers.delete(callback) }; } private notify() { this.subscribers.forEach((callback) => callback(this._value)); } } }
通过这个,你可以使用 `useSyncExternalStore` 将 Observables 连接到 React:
import { useSyncExternalStore } from 'react'; export function useObservable(observable: Observable ) { return useSyncExternalStore( (callback) => observable.subscribe(callback).unsubscribe, () => observable.value ); }
现在,您可以像这样创建和使用**可观察对象**:
const loggedUser = new Observable(user); loggedUser.value // Para acessar o valor dentro do Observable fora do React loggedUser.value = someOtherUser // Para definir o valor, tanto fora quanto dentro do React
在 React 组件内部:
const user = useObservable(loggedUser);
为什么不使用 React Context?
虽然 React Context 在某些情况下有效,但它也有缺点:
使用**Observables**我们可以避免这两个问题!
结束
全局状态管理并不一定很复杂。通过结合 TanStack Query 和轻量级 Observable 模式,您可以简化应用程序,同时避免传统状态管理库的缺陷。