React-Redux用法总结

发布于:2025-02-10 ⋅ 阅读:(14) ⋅ 点赞:(0)

个人笔记

1. 基础概念

1.1 什么是 Redux

Redux 是一个用于 JavaScript 应用的状态管理工具,它帮助你以可预测的方式管理应用状态。

1.2 核心概念

  • Store: 保存数据的地方,整个应用只能有一个 Store
  • Action: 描述发生了什么的普通对象
  • Reducer: 描述如何更新状态的纯函数
  • Dispatch: 发送 action 的方法

2. 基本使用

2.1 安装依赖

npm install redux react-redux @reduxjs/toolkit

2.2 创建 Store

// store/index.js
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from './counterSlice';

export const store = configureStore({
  reducer: {
    counter: counterReducer,
  },
});

2.3 创建 Slice

// store/counterSlice.js
import { createSlice } from '@reduxjs/toolkit';

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;
    },
  },
});

export const { increment, decrement, incrementByAmount } = counterSlice.actions;
export default counterSlice.reducer;

2.4 Provider 配置

// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { store } from './store';
import App from './App';

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

3. 在组件中使用

3.1 使用 Hooks

// components/Counter.js
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { increment, decrement, incrementByAmount } from '../store/counterSlice';

function Counter() {
  // 获取状态
  const count = useSelector((state) => state.counter.value);
  // 获取 dispatch 方法
  const dispatch = useDispatch();

  return (
    <div>
      <h2>Count: {count}</h2>
      <button onClick={() => dispatch(increment())}>
        Increment
      </button>
      <button onClick={() => dispatch(decrement())}>
        Decrement
      </button>
      <button onClick={() => dispatch(incrementByAmount(5))}>
        Add 5
      </button>
    </div>
  );
}

export default Counter;

3.2 异步操作

// store/counterSlice.js
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';

// 创建异步 action
export const fetchCount = createAsyncThunk(
  'counter/fetchCount',
  async (amount) => {
    const response = await fetch(`/api/counter?amount=${amount}`);
    const data = await response.json();
    return data.value;
  }
);

const counterSlice = createSlice({
  name: 'counter',
  initialState: {
    value: 0,
    status: 'idle',
    error: null,
  },
  reducers: {
    // ... 同步 reducers
  },
  extraReducers: (builder) => {
    builder
      .addCase(fetchCount.pending, (state) => {
        state.status = 'loading';
      })
      .addCase(fetchCount.fulfilled, (state, action) => {
        state.status = 'succeeded';
        state.value += action.payload;
      })
      .addCase(fetchCount.rejected, (state, action) => {
        state.status = 'failed';
        state.error = action.error.message;
      });
  },
});

3.3 在组件中使用异步操作

// components/AsyncCounter.js
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { fetchCount } from '../store/counterSlice';

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

  return (
    <div>
      <h2>Async Count: {count}</h2>
      <div>Status: {status}</div>
      {error && <div>Error: {error}</div>}
      <button 
        onClick={() => dispatch(fetchCount(1))}
        disabled={status === 'loading'}
      >
        Fetch Count
      </button>
    </div>
  );
}

export default AsyncCounter;

4. 高级用法

4.1 中间件使用

// store/index.js
import { configureStore } from '@reduxjs/toolkit';
import logger from 'redux-logger';
import counterReducer from './counterSlice';

export const store = configureStore({
  reducer: {
    counter: counterReducer,
  },
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware().concat(logger),
});

4.2 多个 Reducer 的组合

// store/userSlice.js
import { createSlice } from '@reduxjs/toolkit';

const userSlice = createSlice({
  name: 'user',
  initialState: {
    currentUser: null,
    loading: false,
  },
  reducers: {
    setUser: (state, action) => {
      state.currentUser = action.payload;
    },
    clearUser: (state) => {
      state.currentUser = null;
    },
  },
});

export const { setUser, clearUser } = userSlice.actions;
export default userSlice.reducer;

// store/index.js
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from './counterSlice';
import userReducer from './userSlice';

export const store = configureStore({
  reducer: {
    counter: counterReducer,
    user: userReducer,
  },
});

4.3 Selector 优化

// store/selectors.js
import { createSelector } from '@reduxjs/toolkit';

// 基础 selector
const selectCounter = state => state.counter;
const selectUser = state => state.user;

// 复杂 selector
export const selectCounterValue = createSelector(
  [selectCounter],
  counter => counter.value
);

export const selectUserWithCount = createSelector(
  [selectUser, selectCounter],
  (user, counter) => ({
    user: user.currentUser,
    count: counter.value,
  })
);

// 在组件中使用
function UserCounter() {
  const { user, count } = useSelector(selectUserWithCount);
  
  return (
    <div>
      <h3>User: {user?.name}</h3>
      <p>Count: {count}</p>
    </div>
  );
}

5. 最佳实践

5.1 Action 类型常量

// store/types.js
export const COUNTER_TYPES = {
  INCREMENT: 'counter/increment',
  DECREMENT: 'counter/decrement',
  INCREMENT_BY_AMOUNT: 'counter/incrementByAmount',
};

5.2 Action 创建器

// store/actions.js
import { COUNTER_TYPES } from './types';

export const counterActions = {
  increment: () => ({ type: COUNTER_TYPES.INCREMENT }),
  decrement: () => ({ type: COUNTER_TYPES.DECREMENT }),
  incrementByAmount: (amount) => ({
    type: COUNTER_TYPES.INCREMENT_BY_AMOUNT,
    payload: amount,
  }),
};

5.3 TypeScript 支持

// types/store.ts
interface CounterState {
  value: number;
  status: 'idle' | 'loading' | 'succeeded' | 'failed';
  error: string | null;
}

interface RootState {
  counter: CounterState;
  user: UserState;
}

// store/counterSlice.ts
import { createSlice, PayloadAction } from '@reduxjs/toolkit';

const counterSlice = createSlice({
  name: 'counter',
  initialState: {
    value: 0,
    status: 'idle',
    error: null,
  } as CounterState,
  reducers: {
    increment: (state) => {
      state.value += 1;
    },
    incrementByAmount: (state, action: PayloadAction<number>) => {
      state.value += action.payload;
    },
  },
});

6. 性能优化

6.1 避免不必要的渲染

// 使用 shallowEqual 进行浅比较
import { useSelector, shallowEqual } from 'react-redux';

function OptimizedComponent() {
  const { value1, value2 } = useSelector(
    state => ({
      value1: state.counter.value1,
      value2: state.counter.value2,
    }),
    shallowEqual
  );
}

6.2 记忆化选择器

import { createSelector } from '@reduxjs/toolkit';

const selectItems = state => state.items;
const selectFilter = state => state.filter;

const selectFilteredItems = createSelector(
  [selectItems, selectFilter],
  (items, filter) => items.filter(item => item.type === filter)
);

7. 调试工具

7.1 Redux DevTools

// store/index.js
import { configureStore } from '@reduxjs/toolkit';

export const store = configureStore({
  reducer: rootReducer,
  devTools: process.env.NODE_ENV !== 'production',
});

8. 总结

8.1 核心要点

  1. 状态集中管理
  2. 单向数据流
  3. 纯函数更新
  4. 中间件扩展

8.2 使用建议

  1. 合理划分 state 结构
  2. 避免冗余的状态
  3. 使用 TypeScript 增加类型安全
  4. 注意性能优化
  5. 保持 action 和 reducer 的简单性