React 状态管理

104 阅读2分钟

redux主要涉及到的仓库有:redux、redux-toolkit、redux-thunk、react-redux

  • redux是JavaScript应用的状态容器,提供可预测的状态管理;
  • redux-toolkit是redux的工具包,是官方推荐的编写Redux逻辑的方法;
  • redux-thunk是redux的中间件, 使dispatch可以接受函数,赋予其执行异步操作的能力;
  • react-redux为react的redux绑定库, 使react组件可以使用redux,且当 redux store发生变化时,可以自动更新react组件
1、安装依赖
npm i react-redux redux redux-thunk redux-persist
2、目录结构
// 目录结构
src
└───store 
│   └───actions
│   │   │ index.js
│   │   │ xxx.js
│   └───reducers
│   │   │ index.js
│   │   │ xxx.js
│   │ action-types.js
│   │ index.js 
│  index.js
3、状态管理示例

src/index.js 引入状态管理器

import React from "react";
import ReactDOM from "react-dom/client";
import Router from "./router";
import { Provider } from "react-redux";
import { PersistGate } from "redux-persist/integration/react";
import { persistor, store } from "./store";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <Provider store={store}>
    <PersistGate loading={null} persistor={persistor}>
      <Router />
    </PersistGate>
  </Provider>
);

src/store/index.js 创建状态管理器store

import { createStore, applyMiddleware } from "redux";
import reduxThunk from "redux-thunk";
import reducers from "./reducers";
import { persistStore, persistReducer } from "redux-persist";
import storage from "redux-persist/lib/storage";

const persistConfig = {
  key"root",
  storage: storage,
};
// 数据持久化 使用storage,reducers下的index集成多个state数据
const myPersistReducer = persistReducer(persistConfig, reducers);

export const store = createStore(myPersistReducer, applyMiddleware(reduxThunk));
export const persistor = persistStore(store);

src/store/actions/index.js 编写更改state数据的方法

// index.js
import {
  login,
  setUserToken,
  setUserInfo,
  resetUser,
} from "./login";

// 导出所有action方法
export { login, setUserToken, setUserInfo, resetUser };

// xxx.js(login.js)
import * as types from "../action-types";
import { loginAPI } from "@/api/login";
import { setToken, removeToken } from "@/utils/auth";

export const setUserToken = (token) => {
  return {
    type: types.USER_SET_TOKEN,
    token,
  };
};

export const setUserInfo = (userinfo) => {
  return {
    type: types.USER_SET_INFO,
    userinfo,
  };
};

export const resetUser = () => {
  return {
    type: types.USER_RESET_USER,
  };
};

export const login = (data) => (dispatch) => {
  return new Promise((resolve, reject) => {
    loginAPI(data)
      .then((response) => {
        const { data, errmsg, errno } = response;
        if (errno === 200) {
          const token = data.token;
          const userinfo = data.userinfo;
          dispatch(setUserToken(token));
          dispatch(setUserInfo(userinfo));
          setToken(token);
          resolve(response);
        } else {
          const msg = errmsg;
          reject(msg);
        }
      })
      .catch((error) => {
        reject(error);
      });
  });
};

src/store/reducers/index.js 创建存储数据集成多个state

// index.js
import { combineReducers } from "redux";
import user from "./user";

// 导出所有数据到store中存储
export default combineReducers({
  user,
});

// xxx.js(user.js)
import * as types from "../action-types";

const initUser = {
  token"",
  userinfo: {},
};
export default function user(state = initUser, action) {
  switch (action.type) {
    case types.USER_SET_TOKEN:
      return {
        ...state,
        token: action.token,
      };
    case types.USER_SET_INFO:
      return {
        ...state,
        userinfo: action.userinfo,
      };
    case types.USER_RESET_USER:
      return {};
    default:
      return state;
  }
}

src/store/action-types.js 常量配置

// user_info 定义常量使用
export const USER_SET_TOKEN = "USER_SET_TOKEN";
export const USER_SET_INFO = "USER_SET_INFO";
export const USER_RESET_USER = "USER_RESET_USER";

组件内操作store存储的数据

import { useDispatch, useSelector } from "react-redux";

export default Login() {
  const dispatch = useDispatch();
  const { token } = useSelector((state) => state.user);
  
  dispatch(login(data))
      .then((res) => {
        if (res.errno === 200) {
          navigate("/product");
        } else {
          Toast.fail(res.msg);}
      })
      .catch((err) => {
        Toast.fail(err);
      });
}