# 20 在React里使用Redux(网络异步请求)

我们将一步一步通过创建一个简单的项目来学习如何使用 Redux Toolkit、React-Redux 和 React,并模拟从 https://jsonplaceholder.typicode.com/users/1 获取数据的异步请求。我们将构建一个简单的用户信息显示应用。

第1步:创建React应用

首先,你需要安装 Node.js 和 npm(如果还没有安装的话)。接着,使用 create-react-app 创建一个新的 React 应用。

npx create-react-app redux-example
cd redux-example

第2步:安装依赖

在你的项目目录中,安装 @reduxjs/toolkitreact-redux 以及 axios(用于网络请求):

npm install @reduxjs/toolkit react-redux axios

第3步:设置Redux Store

  1. 创建Redux store:在 src 目录下创建一个 app 目录,并在其中创建一个 store.js 文件:
// src/app/store.js
import { configureStore } from '@reduxjs/toolkit';
import userReducer from '../features/user/userSlice';

export const store = configureStore({
  reducer: {
    user: userReducer,
  },
});
  1. 配置Provider:修改 src/index.js 文件来提供 Redux store:
// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { store } from './app/store';
import { Provider } from 'react-redux';

ReactDOM.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>,
  document.getElementById('root')
);

第4步:创建Redux Slice

https://jsonplaceholder.typicode.com/users/1返回内容

{
  "id": 1,
  "name": "Leanne Graham",
  "username": "Bret",
  "email": "Sincere@april.biz",
  "address": {
    "street": "Kulas Light",
    "suite": "Apt. 556",
    "city": "Gwenborough",
    "zipcode": "92998-3874",
    "geo": {
      "lat": "-37.3159",
      "lng": "81.1496"
    }
  },
  "phone": "1-770-736-8031 x56442",
  "website": "hildegard.org",
  "company": {
    "name": "Romaguera-Crona",
    "catchPhrase": "Multi-layered client-server neural-net",
    "bs": "harness real-time e-markets"
  }
}

src 目录下创建一个 features 目录。接着,创建一个 user 目录并在其中创建 userSlice.js

// src/features/user/userSlice.js
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import axios from 'axios';

// 定义异步thunk
export const fetchUser = createAsyncThunk('user/fetchUser', async (arg, { rejectWithValue }) => {
    // arg 参数代表触发这个异步 thunk action 时传递给它的参数。
    // 这意味着,当你调用这个由 createAsyncThunk 创建的异步 action 时,
    // 你可以传递一些数据给它,这些数据通过 arg 参数在 thunk 函数内部可访问。 dispatch(fetchUser(1));

    await new Promise((resolve) => setTimeout(resolve, 2000));

    // 假设有一个 20% 的概率请求失败
    const shouldFail = Math.random() < 0.2;

    if (shouldFail) {
        // 你可以在这里自定义错误信息
        return rejectWithValue('Network request failed');
    }

    try {
        const response = await axios.get('https://jsonplaceholder.typicode.com/users/1');
        return response.data;
    } catch (error) {
        // 如果axios请求失败,也返回一个自定义的错误
        return rejectWithValue(error.response.data || 'Network error occurred');
    }
});

// 创建slice
export const userSlice = createSlice({
  name: 'user',
  initialState: {
    entity: {},
    status: 'idle', // 'idle' | 'loading' | 'succeeded' | 'failed'
  },
  reducers: {},
  extraReducers: (builder) => {
    builder
      .addCase(fetchUser.pending, (state) => {
        state.status = 'loading';
      })
      .addCase(fetchUser.fulfilled, (state, action) => {
        state.entity = action.payload;
        state.status = 'succeeded';
      })
      .addCase(fetchUser.rejected, (state) => {
        state.status = 'failed';
      });
  },
});

export default userSlice.reducer;

第5步:在React组件中使用Redux

  1. 创建一个组件来显示用户信息。在 src 目录下创建一个 features 目录(如果还没有),并在其下创建一个 user 目录。在 user 目录中,创建一个 UserDisplay.js 组件:
// src/features/user/UserDisplay.js
import React, { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { fetchUser } from './userSlice';

export function UserDisplay() {
  const user = useSelector((state) => state.user.entity);
  const status = useSelector((state) => state.user.status);
  const dispatch = useDispatch();

  useEffect(() => {
    dispatch(fetchUser());
  }, [dispatch]);

  return (
    <div>
      {status === 'loading' && <p>Loading...</p>}
      {status === 'succeeded' && (
        <div>
          <h1>{user.name}</h1>
          <p>Email: {user.email}</p>
        </div>
      )}
      {status === 'failed' && <p>Error fetching user.</p>}
    </div>
  );
}
  1. App.js中使用此组件
// src/App.js
import React from 'react';
import { UserDisplay } from './features/user/UserDisplay';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <UserDisplay />
      </header>
    </div>
  );
}

export default App;

这样,你就创建了一个简单的 React 应用,它使用 Redux Toolkit 来管理应用状态,并通过异步 thunk fetchUser 从远程 API 获取用户数据。

第6步:运行你的应用

现在,你可以运行你的应用来看到它的工作情况:

npm start

这将启动开发服务器,并在浏览器中打开你的应用。你应该能看到应用正在加载用户数据,然后显示该数据。

优化和代码风格

为了保证代码的可维护性和可读性,以下是一些推荐的最佳实践:

  • 组织文件结构:我们将代码组织成 app, features 等目录,这有助于保持项目的清晰和模块化。features 目录按功能(或“特性”)组织代码,每个功能有自己的 slice 和组件。
  • 使用异步 thunk 进行数据获取:Redux Toolkit 的 createAsyncThunk 允许你轻松处理异步逻辑,并将结果分派到你的 store。这使得管理复杂的状态更加简单。
  • 使用 React-Redux 的 HooksuseSelectoruseDispatch Hooks 让你能够在组件中轻松访问 Redux store 的状态和分派 action,无需高阶组件或其他连接逻辑。

总结

通过这个示例,你学会了如何使用 Redux Toolkit 和 React-Redux 在 React 应用中管理状态,包括如何发起异步请求并处理结果。这只是 Redux 世界的入门级示例。随着你深入学习,你将会遇到更复杂的状态管理场景,Redux Toolkit 提供了强大的工具和方法来帮助你高效地解决这些问题。

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
React Redux Toolkit 提供了一个名为 `createAsyncThunk` 的工具函数来处理异步操作,它可以帮助我们更轻松地编写异步逻辑。 `createAsyncThunk` 的使用非常简单,我们只需要传入两个参数:一个字符串类型的 action 名称和一个异步函数。例如: ```javascript import { createAsyncThunk } from '@reduxjs/toolkit'; export const fetchUserById = createAsyncThunk( 'users/fetchByIdStatus', async (userId, thunkAPI) => { const response = await fetch(`https://jsonplaceholder.typicode.com/users/${userId}`); return response.json(); } ); ``` 在这个例子中,我们创建了一个名为 `fetchUserById` 的异步 action,它会发起一个网络请求,然后将返回的数据作为 payload 返回。 当我们调用 `fetchUserById` 时,Redux Toolkit 会自动创建三个 action:`fetchUserById/pending`、`fetchUserById/fulfilled` 和 `fetchUserById/rejected`。这些 action 会根据异步操作的状态分别被触发,我们可以在 reducer 中处理它们。 例如,我们可以在 reducer 中处理 `fetchUserById/pending` action,将 `loading` 状态设置为 `true`: ```javascript import { createSlice } from '@reduxjs/toolkit'; import { fetchUserById } from './actions'; const userSlice = createSlice({ name: 'user', initialState: { loading: false, user: null, error: null, }, reducers: {}, extraReducers: (builder) => { builder.addCase(fetchUserById.pending, (state) => { state.loading = true; }); builder.addCase(fetchUserById.fulfilled, (state, action) => { state.loading = false; state.user = action.payload; }); builder.addCase(fetchUserById.rejected, (state, action) => { state.loading = false; state.error = action.error.message; }); }, }); export default userSlice.reducer; ``` 在这个例子中,我们在 `extraReducers` 中处理了三个 action,并根据它们的状态更新了 state。当 `fetchUserById/pending` 被触发时,我们将 `loading` 状态设置为 `true`;当 `fetchUserById/fulfilled` 被触发时,我们将 `loading` 状态设置为 `false`,并将返回的数据保存到 state 中;当 `fetchUserById/rejected` 被触发时,我们将 `loading` 状态设置为 `false`,并将错误信息保存到 state 中。 需要注意的是,`createAsyncThunk` 返回的是一个 Redux action creator,我们可以像普通的 action creator 一样调用它,并且将返回的 action 传递给 `dispatch` 函数来触发异步操作。例如: ```javascript import { useDispatch } from 'react-redux'; import { fetchUserById } from './actions'; function User(props) { const dispatch = useDispatch(); useEffect(() => { dispatch(fetchUserById(1)); }, [dispatch]); return <div>User Component</div>; } ``` 在这个例子中,我们使用 `useDispatch` 钩子获取 `dispatch` 函数,并在 `useEffect` 中调用 `fetchUserById` 来触发异步操作。注意,我们传递的参数是 `1`,这是我们要获取的用户的 ID。当异步操作完成时,Redux Toolkit 会自动触发相应的 action,并将返回的数据保存到 state 中,我们可以在组件中使用 `useSelector` 钩子来获取 state 中的数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值