react、react-redux、redux-thunk、react-saga运用
动机
随着 JavaScript 单页应用开发日趋复杂,JavaScript 需要管理比任何时候都要多的 state (状态)。 这些 state 可能包括服务器响应、缓存数据、本地生成尚未持久化到服务器的数据,也包括 UI 状态,如激活的路由,被选中的标签,是否显示加载动效或者分页器等等。
三大原则
- 单一数据源
整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中。
- State 是只读的
唯一改变 state 的方法就是触发 action,action 是一个用于描述已发生事件的普通对象。
- 使用纯函数来执行修改
为了描述 action 如何改变 state tree ,你需要编写 reducers。
运用
下面,笔都运用一个简单的增加、减少的列子来解读 react-redux 神奇之处。
首先 react-cli 安装一个项目,这块步骤,网上很多教程,就不再继续累赘了。
- 安装 redux 状态管理所需要的模块
npm i -D react-redux redux-thunk
这里解释一下,其实不涉及异步的的 state 状态,不需要 redux-thunk 中间件,这里我们选择带上,是因为一个应用项目肯定会涉及到异步请求。下面来跟着一步步的改造 脚手架生成的项目。(代码编辑器里加粗的是我们要改造的代码块)
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import 'antd/dist/antd.css'; // or 'antd/dist/antd.less'
import { Provider } from 'react-redux';
import Store from './store/index'
const store = Store();
ReactDOM.render(
<Provider store={store}>
<React.StrictMode>
<App />
</React.StrictMode>
</Provider>,
document.getElementById('root')
);
store/index.js
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import reducer from './reducer';
const store = () => createStore(reducer, applyMiddleware(thunk));
export default store;
reducer.js
const initialState = { count: 0 };
const reducer = (state = initialState, action) => {
switch (action.type) {
case 'ADD_CONST':
return { count: state.count + 1 };
case 'MINUS_CONST':
return { count: state.count - 1 };
default:
return state;
}
}
export default reducer;
actions.js
export const addConst = () => {
return {
type: 'ADD_CONST'
}
}
export const minusConst = () => {
return {
type: 'MINUS_CONST'
}
}
CustomCount.js 组件
bindActionCreators 是 redux 的一个 API,作用是将单个或多个 ActionCreator 转化为 dispatch(action) 的函数集合形式。也可以不用 bindActionCreators,dispatch 也是可以的
react-redux的connect方法 接受4个参数
- mapStateToProps(state, [ownProps]) 接受完整的redux状态树作为参数,返回对象的所有key都会成为组件的props
- mapDispatchToProps(dispatch, [ownProps]) 接受redux的dispatch方法作为参数,返回当前组件相关部分的action creator并可以在这里将action creator与props绑定,减少冗余
- mergeProps(stateProps, dispatchProps, ownProps) 如果指定这个函数,你将分别获得 mapStateToProps、 mapDispatchToProps 返回值以及当前组件的props 作为参数,最终返回你期望的、完整的 props
- [options] : pure:true, 将为组件添加shouldComponentUpdate()声明周期函数;
- withRef:false, 若为true,为组件加一个ref值,后续可以使用 getWrappedInstance() 方法来获取该 ref
import React from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as countActions from '../store/action';
class CustomCount extends React.Component {
render() {
const { count, actions } = this.props;
return (
<div>
<span>{count}</span>
<button onClick={actions.addConst}>+</button>
<button onClick={actions.minusConst}>-</button>
</div>
)
}
}
const mapStateToProps = (state) => {
return {
count: state.count
}
}
const mapDispatchToProps = (dispatch) => {
return {
actions: bindActionCreators(countActions, dispatch)
// actions: {
// addConst: () => dispatch(countActions.addConst()),
// minusConst: () => dispatch(countActions.minusConst())
// }
}
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(CustomCount);