redux 相关的基础知识及用法,包括中间件redux-thunk的使用

基础知识点巩固

  • redux三大原则

    • 单一数据源:整个应用的state被存储在一个对象数中,并且这个对象数只存在于唯一的store中。
    • State是只读的:唯一改变state的方法是出发action,action是一个描述已发生事件的普通对象。
    • 使用纯函数来执行修改:编写reducer来描述action如何改变state。
  • 使用redux-thunk来dispatch异步action

  • middleware的作用是在action于reducer之间执行副作用函数,如日志打印(redux-logger),异步函数(redux-thunk),他的优点在于能够链式的插入多个中间件。

目录结构:

(根目录)
  src
    |-assets  // 公共资源
    |-components  // 公共组件
    |-pages  // 页面
    |-router  // 路由
    |-store  // 公共状态管理 redux
      |-action-types.js  // 行为标识(必须是唯一的)
      |-action.js  // 常说的,发起一个action。通过函数传入新的数据,替换之前的store。
      |-reducer.js  // 相当于一个管理员,基于不同的行为标识,修改store中不同的状态。
      |-store.js  // store相当于一个仓库,存储各种数据。这个文件的作用是,整合文件。
  App.js  // 
  index.js  // 入口文件
1. index.js 文件
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { BrowserRouter as Router } from "react-router-dom";

// 还没有用到 redux 的时候,引用 Provider 等,会报错。
// Provider 标签需要放在最外层
import {Provider} from 'react-redux';
import store from "./store/store";
if (module.hot) {
    module.hot.accept();
}
ReactDOM.render(
  <Provider store={store}>
    <Router>
      <App />
    </Router>
  </Provider>
  ,
  document.getElementById('root')
);
2. action-types.js 文件
export const HTMLFONTSIZE = 'HTMLFONTSIZE';
export const DATAONE = 'DATAONE';
export const DATATWO = 'DATATWO';
// ...
3. action.js 文件
/*
没有使用 react-thunk , 只能返回一个对象
*/
// import * as Types from './action-types';
// let actions = {
//   changeFontSize(obj) {
//     return { type: Types.HTMLFONTSIZE, obj }
//   }
// };
// export default actions;

/*
引入thunk插件后,我们可以在actionCreators内部编写逻辑,处理请求结果。而不只是单纯的返回一个action对象。
*/
import * as Types from './action-types';
function changeFontSize(param) {
  return (dispatch) => {
    setTimeout(() => { // 模拟异步(这里可以是一次数据请求)
      dispatch(changeFontSizeAction(param));
    }, 3000)
  }
}

function changeFontSizeAction(obj) {
  return { type: Types.HTMLFONTSIZE, obj }
}

export {
  changeFontSize
};
4. reducer.js 文件
import * as Types from './action-types';

const obj = {
  htmlFontSize: 0
}

function reducer(state = obj, action) {
  switch (action.type) {
    case Types.HTMLFONTSIZE:
      return {...state, ...action.obj};
    default:
      return JSON.parse(JSON.stringify(state));
  }
}
export default reducer;
5. store.js 文件
/*
  import { createStore } from 'redux';
  import reducer from './reducer';
  const store = createStore(reducer);
  // window._store = store; //在window上挂一个叫_store的属性,可以看到store里面的内容
  export default store;
*/

// 使用 thunk 后,可以这样写:
import { createStore, applyMiddleware } from "redux";
import reducer from './reducer';
import thunk from "redux-thunk";
const store = createStore(
  reducer,
  applyMiddleware(thunk)
)
export default store;

使用 thunk 中间件。以及:combineReducers、applyMiddleWare、compose
使用包含自定义功能的 middleware 来扩展 Redux 是一种推荐的方式。 例如,redux-thunk 支持 dispatch function,以此让 action creator 控制反转。 被 dispatch 的 function 会接收 dispatch 作为参数,并且可以异步调用它。 这类的 function 就称为 thunk。另一个 middleware 的示例是 redux-promise。 它支持 dispatch 一个异步的 Promise action,并且在 Promise resolve 后可以 dispatch 一个普通的 action。 compose 可以将中间件组合拼装,使组件更加强大。

使用中间件的 store
import { createStore, combineReducers, applyMiddleware, compose } from "redux";
import thunk from "redux-thunk";
const store = createStore(
  //如果有多个 reducer ,将多个 reducer 整合在一起(项目只有一个reducer时,不建议使用并且会出现错误提示)
  combineReducers(reducer, reducer1, reducer2),
  applyMiddleware(thunk) //可以在 action 中做异步处理 dispatch
  //如果有多个中间件就可以这样写:compose(applyMiddleware(thunk), xxxx, xxxxx)
)

这样,就可以使用 redux 了。
在此之前,我们习惯:哪里需要用到接口,就在哪个页面(文件)中调取。
现在,通过中间件 thunk 可以让程序员在 action 中调用接口。
下面具体说一下,中间件 thunk 的使用方式。

使用 applyMiddleware(thunk) 之后,action 中可以这样写:
import * as Types from './action-types';
  function getList(param) {
    return (dispatch) => {
      setTimeout(() => {     // 模拟异步(这里可以是一次数据请求)
        dispatch listData(param)
      }, 5000)
    }
  }
  function listData(obj) {
    return { type: Types.LISTDATA, obj }
  }
export {
  getList
};
项目组件中使用的例子:
import { getList } from "../../store/store";
import React, { Component } from "react";
import "./BaseEchart.less";
import connect from "react-redux/es/connect/connect";
class BaseEchart extends Component {
  constructor(props) {
    super(props);
  };
  componentDidMount() {
    const param = {
      startTime: "2019-10-20 12:00:00",
      endTime: "2019-10-21 12:00:00"
    }
    this.props.getList(param)
  }
  // UNSAFE_componentWillMount,
  componentWillReceiveProps(nextProps) {
    if (nextProps.listData !== this.props.listData) {
      console.log(nextProps.actions.listData)
    }
  }
  //componentWillUnmount() {}
  render() {
    return (
      <div className="BaseEchart">
      </div>
    )
  }
}
export default connect(state => state, {getList})(BaseEchart);
posted @ 2020-12-17 19:14  真的想不出来  阅读(185)  评论(0编辑  收藏  举报