// Demo.jsx import React from 'react'; import { changeAge, changeUser } from './actionCreate'; import { connect } from './react-redux'; import './style.css'; // 编写 mapStateToProps 参数 redux state 返回所需的 redux state const mapStateToProps = (state) => { return {user: state.user, age: state.age}; } // 调用高阶组件 @connect(mapStateToProps, {changeAge, changeUser}) export default class Demo extends React.Component{ onChange = (e) => { this.props.changeUser(e.target.value); } onClick = () => { this.props.changeAge(); } render(){ return ( <div> <p>user: {this.props.user}, age: {this.props.age}</p> user: <input type="text" className="input" onChange={this.onChange}/> <button className="btn" onClick={this.onClick}>年龄增长</button> </div> ); } }
四、redux API bindactioncreators 的实现
在上文我们对 mapDispatchToProps 的处理过程就是 API bindactioncreators 的功能: 将给定 action 创建函数使用 dispatch 进行包裹后返回;
封装 bindactioncreators// redux.js export const bindactioncreators = (mapDispatchToProps, dispatch) => { const actionFun = {}; // 遍历 mapDispatchToProps 中每个 action 创建函数 并使用 dispatch 包裹后返回 for(let key in mapDispatchToProps){ actionFun[key] = (...args) => { dispatch(mapDispatchToProps[key](...args)); } } return actionFun; // 一种简写方式: 骚操作 // return actionFun = Object.keys(mapDispatchToProps) // .reduce((total, item) => { // return { ...total, [item]: (...args) => {dispatch(mapDispatchToProps[item](...args));} // } } ,{}); }
修改 connect :// react-redux.js import { bindactioncreators } from './redux'; .... export const connect = (mapStateToProps, mapDispatchToProps) => (Component) => { return class NewComponent extends React.Component{ static contextTypes = { store: propTypes.object }; constructor(props, context){ super(props, context); this.store = context.store; this.state = {}; } componentDidMount(){ this.store.subscribe(this.update); this.update(); } update = () => { const state = this.store.getState(); const filterState = mapStateToProps(state); // 调用 API bindactioncreators // 对 mapDispatchToProps 内每个 action 创建函数使用 dispatch 进行包裹后返回 const actionFun = bindactioncreators(mapDispatchToProps, this.store.dispatch); this.setState({...filterState, ...actionFun}); } render(){ return <Component {...this.state} /> } } }
五、redux API applyMiddleware 的实现
到此简化版的 react-redux 算是已经初步完成,但是假如我们想要我们的 age 值的增长是一个异步操作,比如:通过按钮点击后经过两秒再修改 age ,而不是一点击按钮就立即修改值;这样我们又该怎么实现呢?
当然我们可以通过 setTimeout 两秒后再执行 action 创建函数,比如这样:
onClick = () => { setTimeout(()=>{ // 两秒后执行 action 创建函数 this.props.changeAge(); }, 2000); }
但是呢事实上我们并不愿意像上面那么整,我们想要这么一种效果:我们只需要简单的调用 action 创建函数即可实现异步操作,而不是需要进行额外的操作;这时我们就需要为我们的 react-redux 编写一个中间件来实现这么一个效果;
5.1 准备工作
新增action 创建函数在这之前我们所有的 acton 创建函数都是直接返回一个 action 对象,下面我们写一个不一样的 action 创建函数, 它返回的不再是一个 action 对象而是一个函数,并且该函数接收两个参数 dispatch 以及 getState, 在该函数内部我们进行相应的异步操作,比如:修改 age 值;
// actionCreate.js export const asyncChangeAge = () => { // 返回函数 return (dispatch, getState) => { setTimeout(v=>{ console.log('==>', getState()); dispatch({type: 'AGE_GROW'}); }, 1000); } }
修改页面:新增按钮并绑定点击事件,并且调用 asyncChangeAge 函数;// Demo.jsx // Demo.jsx import React from 'react'; import './style.css'; // 导入 asyncChangeAge import { changeAge, changeUser, asyncChangeAge } from './actionCreate'; import { connect } from './react-redux'; const mapStateToProps = (state) => { return {user: state.user, age: state.age}; } // 添加 asyncChangeAge @connect(mapStateToProps, {changeAge, changeUser, asyncChangeAge}) export default class Demo extends React.Component{ onChange = (e) => { this.props.changeUser(e.target.value); } onClick = () => { this.props.changeAge(); } // 点击事件 onClickAsync = () => { this.props.asyncChangeAge(); } render(){ return ( <div> <p>user: {this.props.user}, age: {this.props.age}</p> user: <input type="text" className="input" onChange={this.onChange}/> <button className="btn" onClick={this.onClick}>年龄增长</button> {/* 新增按钮 */} <button className="btn" onClick={this.onClickAsync}> 异步增长 </button> </div> ); } }
页面的变化其实很简单就是新增了一个按钮:5.2 需求实现