redux

227 阅读3分钟

随着 JavaScript 单页应用开发日趋复杂,JavaScript 需要管理比任何时候都要多的 state (状态) 。 这些 state 可能包括服务器响应、缓存数据、本地生成尚未持久化到服务器的数据,也包括 UI 状态,如激活的路由,被选中的标签,是否显示加载动效或者分页器等等。Redux基本概念主要有以下几个:

Store

Store就是一个仓库,它存储了所有的状态(State),还提供了一些操作他的API,我们后续的操作其实都是在操作这个仓库。 store 是应用状态 state 的管理者,包含下列四个函数:

  • getState() 获取整个 state
  • dispatch(action) 触发 state 改变的唯一途径
  • subscribe(listener) 可以理解成是 DOM 中的 addEventListener
  • replaceReducer(nextReducer) 一般在 Webpack Code-Splitting 按需加载的时候用

state和store的关系:state = store.getState()

Actions

Action 是把数据从应用传到 store 的有效载荷。它是 store 数据的唯一来源。一般来说你会通过 store.dispatch() 将 action 传到 store。

一个Action就是一个动作,这个动作的目的是更改Store中的某个状态,Store还是上面的那个仓库,现在我想往书架放一本书,那"我想往书架放一本书"就是一个Action,代码就是这样:

{
type: "PUT_BOOK",
count: 1
}

Reducer

Reducers 指定了应用状态的变化如何响应actions并发送到 store 的,记住 actions 只是描述了有事情发生了这一事实,并没有描述应用如何更新 state。 正如前面"我想往往书架放一本书"只是想了,还没操作,具体操作要靠Reducer,Reducer就是根据接收的Action来改变Store中的状态,比如我接收了一个PUT_BOOK,同时数量count是1,那放进去的结果就是book增加了1,从0变成了1,代码就是这样:


function reducer(state = { book : 0 }, action) {
  switch (action.type) {
    case 'PUT_BOOK':
      return {...state, book: state.book + action.count}
    default:
      return state
  }
}

认识一下redux在实际开发中的流程:

image.png

在项目中使用redux

在src目录中新建store文件夹:

添加index.js文件:

import { createStore, applyMiddleware, compose } from "redux";
import thunk from "redux-thunk";
import reducer from "./reducer";

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

const store = createStore(reducer, composeEnhancers(applyMiddleware(thunk))); //合并中间件  applyMiddleware

export default store

添加reducer.js文件:

import { combineReducers } from "redux-immutable"; //合成reducer

import { reducer as recommendReducer } from "../pages/discover/c-pages/recommend/store";
import { reducer as playerReducer } from "../pages/player/store";

const cReducer = combineReducers({
  recommend: recommendReducer,
  player: playerReducer,
});

export default cReducer;

在项目目标page中添加store文件夹,方便管理:

新建actionCreators.js文件:

import * as actionTypes from "./constants";
import {
  getTopBanners,
  getHotRecommends,
} from "@/services/recommend"; //网络请求

const changeTopBannerAction = (res) => ({
  type: actionTypes.CHANGE_TOP_BANNERS,
  topBanners: res.banners,
});
const changeHotRecommendAction = (res) => ({
  type: actionTypes.CHANGE_HOT_RECOMMEND,
  hotRecommends: res.result,
});

export const getTopBannerAction = () => {
  return (dispatch) => {
    getTopBanners().then((res) => {
      dispatch(changeTopBannerAction(res));
    });
  };
};
export const getHotRecommendAction = (limit) => {
  return (dispatch) => {
    getHotRecommends(limit).then((res) => {
      dispatch(changeHotRecommendAction(res));
    });
  };
};

新建constants.js文件:

export const CHANGE_TOP_BANNERS = "recommend/CHANGE_TOP_BANNERS"
export const CHANGE_HOT_RECOMMEND = "recommend/CHANGE_HOT_RECOMMEND"

新建index.js文件(导出reducer):

import reducer from './reducer'
export {
  reducer
}

新建reducer.js文件:

import { Map } from "immutable";

import * as actionTypes from "./constants";

const defaultState = Map({
  topBanners: [],
  hotRecommends: [],
});

function reducer(state = defaultState, action) {
  switch (action.type) {
    case actionTypes.CHANGE_TOP_BANNERS:
      return state.set("topBanners", action.topBanners);
    case actionTypes.CHANGE_HOT_RECOMMEND:
      return state.set("hotRecommends", action.hotRecommends);
    default:
      return state;
  }
}

export default reducer;

上述代码中的 immutable

1.一旦创建,就不能更改的数据,对immutable对象的任何修改或删除添加都会返回一个新的immutable对象
2.实现原理就是持久化数据结构,在使用旧数据创建新数据的时候,会保证旧数据同时可用且不变,同时为了避免深度复制复制所有节点的带来的性能损耗,immutable使用了结构共享,即如果对象树种的一个节点发生变化,只修改这个节点和受他影响的父节点,其他节点则共享。

在组件中使用:

import { shallowEqual, useDispatch, useSelector } from "react-redux";
import { getHotRecommendAction } from "../../store/actionCreators";
// redux hooks
  const { hotRecommends } = useSelector(
    (state) => ({
      hotRecommends: state.getIn(["recommend", "hotRecommends"]),
    }),
    shallowEqual
  );
  const dispatch = useDispatch();

  // other hooks

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

useSelector 作用:共享状态,从Redux的store中提取数据(state)

const num=useSelector(state=>state.num)具体可以看看:www.5axxw.com/questions/c…