重新认识React状态本质
React 的状态(State)是组件内部管理动态数据的核心机制,它不仅是数据容器,更是视图更新的触发器。是react项目中最重要没有之一的一种数据,说白了,这个所谓的状态变了,页面就变,非状态的数据变了页面不会有任何变化,只要处理好:引起状态变化=>状态变化处理=>状态变化反映到页面中这个核心流程,就能写出高性能的页面。
状态的核心特征
- 响应性:状态与视图自动保持同步
- 局部性:默认隔离在组件作用域内
- 可预测性:通过setState等API进行受控变更
状态提升的六大途径
React提供了多维度的状态管理方案:
- 组件内状态 :
useState
/useReducer
- 组件间传递 :
Props Drilling
- 全局共享 :
Context API
- 外部存储 :
useSyncExternalStore
- 状态库集成 :
Redux/Zustand
等 - 服务端同步 :
TanStack Query
现代状态管理分层架构
React中的状态可以分为全局状态和局部状态,局部状态就是组件中私有的状态比如一个计数器组件中的"数",全局状态说白了就是一些需要深层级传递的状态。那么什么是状态管理呢?其实就是用类似Context Api和Redux、zustand这种库来把一些需要深层级传递的状态收集起来,方便后续项目中使用。
而全局状态又可以分成两种类型:客户端状态和服务端状态,前者只存在于应用程序内部,而后者在应用程序外部持久存在,所以显而易见,状态管理也应该区分开两种情况。其中客户端状态使用zustand等库就可以完美进行管理,要优雅的处理服务端的状态就要用到Tanstack Query
这个库了。
客户端状态管理(zustand最佳实践)
什么叫只存在应用程序内部呢?举个例子,UI交互状态(弹窗开关、表单填写)、主题配色方案、本地用户偏好设置等等。zustand的store也只应该存储这些。来看一下合理的实践。
简单的几行代码,就托管了
theme
这个客户端状态
我自己以前在平时项目开发中经常将请求中拿过来的一堆数据存在上面那些工具中,给项目的store创造了一个个schema,然后用着很爽,类型还安全。殊不知这样处理项目中的状态结构十分混乱,非常不利于后续的维护。其实是弄混了客户端状态与服务端状态的定位。
服务端状态管理(TanStack Query深度整合)
在应用程序外部持久存在,换句话说,就是你从服务端靠请求拿到的需要显示在页面上的数据。
我们先来看下如何使用tanstack query
js
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
// 创建一个`QueryClient`实例,该实例可以理解为zustand的那种全局的store
const queryClient = new QueryClient()
function App() {
return (
// 将该实例传入到QueryClientProvider中 ,像context那样在根组件上包一层
<QueryClientProvider client={queryClient}>
<Test />
</QueryClientProvider>
)
}
在这里创建的这个QueryClient
实例后面我们就可以用useQueryClient
来拿到从而对存入里面的服务端状态进行一些神奇的处理,比如乐观更新等等。
我们来看一下基本的使用:
在上图中展示了useQuery
和useMutation
这两个最重要的hook。
useQuery
需要我们提供querykey(一个数组)以及一个返回promise的queryFn,querykey可以理解为在刚刚创建好的QueryClient
中对这个query的唯一标识,后面通过这个querykey我们可以从QueryClient
取出这个key对应的数据或者对这个query存储的数据进行更改或者重新验证。该hook返回query,该对象中保存着对于这次查询你所应该知道的所有数据包括
data
:本次查询返回的数据。error
:请求失败时对应的错误对象。isPending
/status === 'pending'
:还没有数据。isError
/status === 'error'
:请求出错。isSuccess
/status === 'success'
:请求成功并且数据可用状态。isFetching
/fetchStatus === 'fetching'
:正在请求数据中。isPaused
/fetchStatus === 'paused'
:请求暂停中。fetchStatus === 'idle'
:当前没有任何请求,处于空闲中。
useMutation
接受一个mutationFn和突变后的回调,和useQuery
类似,他返回一个mutation对象,通过该对象你可以得到这次突变所有状态信息,并且可以调用上面的mutate方法发起一次突变。
tanstack query
通过一个请求库的存在形式,帮您在项目中发出一切请求,然后自动的缓存他们,通过开发者的配置可以更改缓存的时间,重试的次数等等,让项目中的服务端状态系统的管理起来,让全局状态更加的清晰。
In this situation it's important to note that TanStack Query is not a replacement for local/client state management. However, you can use TanStack Query alongside most client state managers with zero issues.
需要注意的是,TanStack Query 不能替代本地/客户端状态管理(比如 Zustand、Mobx、Valtio 等)。但是,您可以将 TanStack 查询与大多数客户端状态管理库一起使用,而不会出现任何问题。
在当前React生态中,状态管理已从单一方案发展为分层架构。建议将75%的服务端状态交由TanStack Query管理,20%的UI状态使用zustand处理,剩余5%的派生状态通过useMemo
优化。这种黄金分割比例既能保证代码可维护性,又能获得最佳运行时性能。