You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Redux Toolkit中如何创建client文件并将请求数据存入state

Redux异步拉取数据存储操作指引

一、创建src/api/client请求工具

这个client本质是统一封装的HTTP请求工具,没有强制实现标准,只要支持Promise风格调用、返回结构和你thunk里的取值逻辑匹配即可。

  • 先在src目录下新建api文件夹,在文件夹内新建client.js文件
  • 可以选择原生fetch封装(和官方示例逻辑完全对齐),代码如下:
// src/api/client.js
export async function client(url, { method = 'GET', data, headers: customHeaders } = {}) {
  const headers = {
    'Content-Type': 'application/json',
    ...customHeaders
  }
  const config = { method, headers }

  // 非GET请求序列化参数到请求体
  if (method !== 'GET' && data) {
    config.body = JSON.stringify(data)
  }

  const res = await fetch(url, config)
  // 统一错误处理
  if (!res.ok) {
    const errData = await res.json().catch(() => ({}))
    return Promise.reject({ status: res.status, ...errData })
  }
  // 统一返回格式,对齐示例中response.data的取值逻辑
  const resData = await res.json()
  return { data: resData }
}

// 绑定快捷调用方法
client.get = (url, config = {}) => client(url, { ...config, method: 'GET' })
client.post = (url, data, config = {}) => client(url, { ...config, method: 'POST', data })
client.put = (url, data, config = {}) => client(url, { ...config, method: 'PUT', data })
client.delete = (url, config = {}) => client(url, { ...config, method: 'DELETE' })
  • 如果习惯用axios,也可以直接用axios生成实例作为client,不需要手写封装,先执行npm install axios安装依赖,再写如下代码即可:
// src/api/client.js  axios版本
import axios from 'axios'
export const client = axios.create({
  baseURL: '' // 可配置接口公共前缀,比如'/api'
})

后续如果需要加token携带、请求响应拦截,直接在这个文件里统一修改即可。

二、将接口返回数据存入Redux state实现全局复用

createAsyncThunk执行时会自动派发三个状态的action:请求发起(pending)、请求成功(fulfilled)、请求失败(rejected),你只需要在slice的extraReducers里监听这三个action,把数据更新到state中即可,全应用所有组件都可以直接从store读取这份数据。

  1. 补全postsSlice的完整逻辑,核心是在extraReducers里处理成功回调,把接口返回值存入state:
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'
import { client } from '../../api/client'

const initialState = {
  posts: [],
  status: 'idle', // 状态枚举:idle(空闲未请求)/loading(请求中)/succeeded(请求成功)/failed(请求失败)
  error: null
}

// 异步thunk保持原有逻辑即可
export const fetchPosts = createAsyncThunk('posts/fetchPosts', async () => {
  const response = await client.get('/fakeApi/posts')
  return response.data
})

const postsSlice = createSlice({
  name: 'posts',
  initialState,
  reducers: {
    // 其他同步操作的reducer写在这里,比如新增、编辑、删除帖子
  },
  extraReducers(builder) {
    builder
      // 请求发起时更新状态为加载中
      .addCase(fetchPosts.pending, (state) => {
        state.status = 'loading'
      })
      // 请求成功时把返回数据存入state.posts
      .addCase(fetchPosts.fulfilled, (state, action) => {
        state.status = 'succeeded'
        // action.payload就是thunk中return的接口返回数据
        // 全量覆盖场景直接赋值:state.posts = action.payload
        // 追加场景用concat:state.posts = state.posts.concat(action.payload)
        state.posts = action.payload
      })
      // 请求失败时存储错误信息
      .addCase(fetchPosts.rejected, (state, action) => {
        state.status = 'failed'
        state.error = action.error.message
      })
  }
})

export default postsSlice.reducer
// 导出selector方便组件读取state,避免组件里重复写state路径
export const selectAllPosts = state => state.posts.posts
export const selectPostsStatus = state => state.posts.status
export const selectPostsError = state => state.posts.error
  1. 在store配置中注册该slice的reducer,保证posts节点挂载到根store上。
  2. 组件中触发请求、读取数据的示例:
import { useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { fetchPosts, selectAllPosts, selectPostsStatus, selectPostsError } from './postsSlice'

export default function PostsList() {
  const dispatch = useDispatch()
  const posts = useSelector(selectAllPosts)
  const status = useSelector(selectPostsStatus)
  const error = useSelector(selectPostsError)

  useEffect(() => {
    // 仅在空闲状态触发请求,避免重复拉取
    if (status === 'idle') {
      dispatch(fetchPosts())
    }
  }, [status, dispatch])

  if (status === 'loading') return <div>帖子加载中...</div>
  if (status === 'failed') return <div>加载失败:{error}</div>

  return (
    <div className="posts-list">
      {posts.map(post => (
        <div key={post.id} className="post-item">
          <h3>{post.title}</h3>
          <p>{post.content}</p>
        </div>
      ))}
    </div>
  )
}

注意:Redux Toolkit内置了Immer,在reducer中直接修改state属性、调用数组的可变方法(push、concat等)都是安全的,不需要手动做不可变数据拷贝。

其他任何组件需要用到帖子数据时,只需要用useSelector(selectAllPosts)即可直接读取全局store中存储的帖子列表,不需要重复发起请求。

内容的提问来源于stack exchange,提问作者Sara Jalal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 18:21:56