React redux使用实例

79 阅读3分钟

一.涉及到的插件

redux 提供createStore和applyMiddleware react-redux 它能让react组件从redux store读取数据 , 并且分发action到store来更新数据 redux-thunk 网络等异步任务不可或缺的中间件

redux-immutable 引入combineReducers,将combineReducers内的reducer也转换成immutable对象,统一数据格式

二.应用结构

demo地址

​
    |-- src
        |-- App.js
        |-- index.js
        |-- pages
        |   |-- discover
        |   |   |-- c-pages
        |   |       |-- album
        |   |       |   |-- store
        |   |       |       |-- actionCreators.js
        |   |       |       |-- constants.js
        |   |       |       |-- index.js
        |   |       |       |-- reducer.js
        |   |       |-- artist
        |   |       |   |-- store
        |   |       |       |-- actionCreators.js
        |   |       |       |-- constants.js
        |   |       |       |-- index.js
        |   |       |       |-- reducer.js
        |   |       |       
        |   |       |-- djradio
        |   |       |   |-- store
        |   |       |       |-- actionCreators.js
        |   |       |       |-- constants.js
        |   |       |       |-- index.js
        |   |       |       |-- reducer.js
        |   |       |       
        |   |       |-- ranking
        |   |       |   |-- store
        |   |       |       |-- actionCreators.js
        |   |       |       |-- constants.js
        |   |       |       |-- index.js
        |   |       |       |-- reducer.js
        |   |       |       
        |   |       |-- recommend
        |   |       |   |-- store
        |   |       |       |-- actionCreators.js
        |   |       |       |-- constants.js
        |   |       |       |-- index.js
        |   |       |       |-- reducer.js
        |   |       |       
        |   |       |-- songs
        |   |           |-- store
        |   |               |-- actionCreators.js
        |   |               |-- constants.js
        |   |               |-- index.js
        |   |               |-- reducer.js
        |   |-- player
        |       |-- store
        |           |-- actionCreators.js
        |           |-- constants.js
        |           |-- index.js
        |           |-- reducer.js
        |-- store
        |   |-- index.js
        |   |-- reducer.js

三.使用步骤

1.定义入口文件(App.js)

从react-redux引入Provider,Provider 负责将 store 传递给内部所有组件

要将自己的app包含在Provider中 , redux store才会生效。

import React from 'react';
//Provider 负责将 store 传递给内部所有组件
import { Provider } from "react-redux";
//引入定义好的状态管理器
import store from "./store";
//引入自己的app
import HYMain from './pages/main';
​
function App() {
  return (
    <Provider store={store}>
      <HYMain/>
    </Provider>
  );
}
​
export default App;

2.定义store(/src/store)

reducer.js:用于将子模块的reducer合并

index.js: 包装reducer,统一暴露出口

    store
      |-- index.js
      |-- reducer.js

reducer.js

import { combineReducers } from "redux-immutable";
//app使用到的reducer
import { reducer as recommendReducer } from "../pages/discover/c-pages/recommend/store";
import { reducer as playerReducer } from "../pages/player/store";
...
//将combineReducers内的reducer也转换成immutable对象
export default combineReducers({
  recommend: recommendReducer,
  player: playerReducer,
    ...
})

index.js

createStore:创建一个 Redux store 来以存放应用中所有的 state。createStore(reducer, [preloadedState], [enhancer])

applyMiddleware :将所有中间件组成一个数组,依次执行。applyMiddleware(...middleware)

thunk:处理网络等异步任务不可或缺的中间件,

compose:从右到左来组合多个函数。compose(...functions)

import { createStore, compose, applyMiddleware } 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)
));
​
export default store;
​

3.定义模块的store

actionCreators:action的统一管理文件

constants:常量管理文件,用于声明事件名称

reducer:事件触发器

index:store入口

|-- player
    |-- store
        |-- actionCreators.js
        |-- constants.js
        |-- index.js
        |-- reducer.js

actionCreators.js

当前项目的action分为两类

第一种:偏向无业务逻辑,只对返回actionType和入参,也就是只对state做赋值操作

第二类:偏向业务逻辑,可以做逻辑判断,接口调用等等。调用第一种ation来间接操作state

import * as actionTypes from './constants';
//第一类
export const demoAction = (params) => ({
    type: actionTypes.DEMO,
    params
})
//第二类
export const xxxAction = () => {
    //返回函数的入参(dispatch, getState)
    //dispatch用于派发action事件,getState用于获取state里的值
  return (dispatch, getState) => {
   const id=getState().getIn(["moduleA","demoId"])
   getById(id).then(res=>{
       dispatch(demoAction(res));
   })
  }
}

示例代码

​
const changeSimiSongsAction = (res) => ({
  type: actionTypes.CHANGE_SIMI_SONGS,
  simiSongs: res.songs
})
​
export const getSimiSongAction = () => {
  return (dispatch, getState) => {
    const id = getState().getIn(["player", "currentSong"]).id;
    if (!id) return;
​
    getSimiSong(id).then(res => {
      dispatch(changeSimiSongsAction(res));
    })
  }
}

constants.js

一般用于定义派发事件的type

export const CHANGE_SIMI_PLAYLIST = "player/CHANGE_SIMI_PLAYLIST";
export const CHANGE_SIMI_SONGS = "player/CHANGE_SIMI_SONGS";

reducer.js

//用于存储state的数据结构
import { Map } from 'immutable';
import * as actionTypes from './constants';
//state
const defaultState = Map({
    playList:[],
    simiSongs:[]
})
//定义reducer,用于接收派发事件
function reducer(state = defaultState, action) {
  switch (action.type) {
    case actionTypes.CHANGE_SIMI_PLAYLIST:
      return state.set("simiPlaylist", action.simiPlaylist);
    case actionTypes.CHANGE_SIMI_SONGS:
      return state.set("simiSongs", action.simiSongs);
    default:
      return state;
  }
}
export default reducer;

4.在模块中使用

useSelector:可以连接redux,获取其state。(第二个入参为其更新依赖)

shallowEqual:浅层对比,一般搭配useSelector使用,作为其第二个入参。

useDispatch:执行得到dispatch方法

import { useSelector, shallowEqual, useDispatch } from 'react-redux';
import  { useEffect } from 'react';
  const {
    currentSong,
    playList,
  } = useSelector(state => ({
    currentSong: state.getIn(["player", "currentSong"]),
    playList: state.getIn(["player", "playList"]),
  }), shallowEqual);
//获取dispatch方法
const dispatch = useDispatch();
//更新依赖项为dispatch,当useDispatch()执行之后,useEffect函数会被更新
  useEffect(() => {
    dispatch(getSongDetailAction(167876));
  }, [dispatch]);