《React状态管理之 - toolkit & react-redux》

84 阅读1分钟

情况一:非异步请求

第一步:创建切片slice

import { createSlice, configureStore } from '@reduxjs/toolkit';
export const counterSlice = createSlice({
    name: 'counter',
    initialState: {
        value: 0
    },
    reducers: {
        increment: state => {
            state.value += 1;
        },
        decrement: state => {
            state.value -= 1;
        },
        incrementByAmount: (state, action) => {
            state.value += action.payload;
        }
    }
});

第二步:配置 store

const store = configureStore({
    reducer: {
        counter: counterSlice.reducer
    }
});

第三步:在组件中使用

import { useSelector, useDispatch } from 'react-redux';
import { counterSlice } from './counterSlice.js';

function Counter() {
    const count = useSelector(state => state.counter.value);
    const dispatch = useDispatch();

    return (
        <div>
            <button
                onClick={() => dispatch(counterSlice.actions.increment())}
            >
                Increment
            </button>
            <span>{count}</span>
            <button
                onClick={() => dispatch(counterSlice.actions.decrement())}
            >
                Decrement
            </button>
        </div>
    );
}

情况二:异步请求(createAsyncThunk)

第一步:创建createAsyncThunk

import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';

// 创建异步 action
export const fetchUserById = createAsyncThunk(
    'users/fetchById',
    async (userId, { rejectWithValue }) => {
        try {
            const response = await fetch(`/api/users/${userId}`);
            if (!response.ok) {
                throw new Error('Network response was not ok');
            }
            return await response.json();
        } catch (error) {
            return rejectWithValue(error.message);
        }
    }
);

第二步:创建slice

const userSlice = createSlice({
    name: 'user',
    initialState: {
        data: null,
        loading: false,
        error: null
    },
    reducers: {
        // 同步 reducers
        clearUser: (state) => {
            state.data = null;
        }
    },
    extraReducers: (builder) => {
        builder
            .addCase(fetchUserById.pending, (state) => {
                state.loading = true;
                state.error = null;
            })
            .addCase(fetchUserById.fulfilled, (state, action) => {
                state.loading = false;
                state.data = action.payload;
            })
            .addCase(fetchUserById.rejected, (state, action) => {
                state.loading = false;
                state.error = action.payload;
            });
    }
});

第三步:在组件中使用

// UserProfile.jsx
import { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
// 需要引入 fetchUserById action
import { fetchUserById } from './userSlice';  // 确保路径正确

function UserProfile({ userId }) {
    const dispatch = useDispatch();
    const { data, loading, error } = useSelector(state => state.user);

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

    if (loading) return <div>Loading...</div>;
    if (error) return <div>Error: {error}</div>;
    if (!data) return null;

    return (
        <div>
            <h2>{data.name}</h2>
            <p>{data.email}</p>
        </div>
    );
}

export default UserProfile;