【React进阶系列】手写实现react-redux api

2019-01-25  本文已影响0人  Rainie_1fb7

简介:简单实现react-redux基础api

react-redux api回顾

<Provider store>

把store放在context里,所有子组件可以直接拿到store数据

使组件层级中的 connect() 方法都能够获得 Redux store根组件应该嵌套在中

ReactDOM.render(,  rootEl)ReactDOM.render(,  document.getElementById('root'))

connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])

链接组件和数据,把redux中的数据放到组件的属性中

[mapStateToProps(state, [ownProps]): stateProps] (Function)

如果定义该参数,组件将会监听 Redux store 的变化。任何时候,只要 Redux store 发生改变,mapStateToProps 函数就会被调用。该回调函数必须返回一个纯对象,这个对象会与组件的 props 合并

如果你省略了这个参数,你的组件将不会监听 Redux store 

ownProps,则该参数的值为传递到组件的 props,而且只要组件接收到新的 props,mapStateToProps 也会被调用,被重新计算

mapStateToProps 函数的第一个参数是整个Redux store的state,它返回一个要作为 props 传递的对象。它通常被称作 selector (选择器)。 可以使用reselect去有效地组合选择器和计算衍生数据.

注意:如果定义一个包含强制性参数函数(这个函数的长度为 1)时,ownProps 不会传到 mapStateToProps

constmapStateToProps =(state, ownProps) =>{return{    active: ownProps.filter === state.visibilityFilter  }}

[mapDispatchToProps(dispatch, [ownProps]): dispatchProps] (Object or Function)

Object: 它的每个键名也是对应 UI 组件的同名参数,键值应该是一个函数(actioncreator),会被当作Actioncreator ,返回的Action会由 Redux 自动发出,Function: 会得到dispatch和ownProps(容器组件的props对象)两个参数(此时可能用到Redux 的辅助函数 bindActionCreators())

省略这个 mapDispatchToProps 参数,默认情况下,dispatch 会注入到你的组件 props 中,你可以this.props.dispatch调用

指定了该回调函数中第二个参数 ownProps,该参数的值为传递到组件的 props,而且只要组件接收到新 props,mapDispatchToProps 也会被调用

eg:

connect(mapStateToProps, {  hideAdPanel,  pushAdData,})(AdPanel)functionmapDispatchToProps(dispatch){return{    todoActions: bindActionCreators(todoActionCreators, dispatch),    counterActions: bindActionCreators(counterActionCreators, dispatch)  }}

知识点补充 - React高阶组件(Higher-Order Components)

高阶组件就是一个函数,且该函数接受一个组件作为参数,并返回一个新的组件

高阶组件就是一个没有副作用的纯函数

使用场景:两个组件大部分代码都是重复的+且更好的封闭性,不需要关注数据的获取

importReact, {Component} from'react'classWelcomeextendsComponent{    constructor(props) {super(props);this.state = {            username: ''        }    }    componentWillMount() {        let username = localStorage.getItem('username');this.setState({            username: username        })    }    render() {return(           

welcome {this.state.username}        )    }}exportdefaultWelcome;importReact, {Component} from'react'classGoodbyeextendsComponent{    constructor(props) {super(props);this.state = {            username: ''        }    }    componentWillMount() {        let username = localStorage.getItem('username');this.setState({            username: username        })    }    render() {return(            goodbye {this.state.username}        )    }}exportdefaultGoodbye;

welcome和goodbye组件相似,只能获取的数据不一样,用高阶组件,提取公共部分

importReact, {Component} from'react'exportdefault(WrappedComponent) => {classNewComponentextendsComponent{        constructor() {super();this.state = {                username: ''            }        }        componentWillMount() {            let username = localStorage.getItem('username');this.setState({                username: username            })        }        render() {return        }    }returnNewComponent}简化welcome和goodbyeimportReact, {Component} from'react';importwrapWithUsername from'wrapWithUsername';classWelcomeextendsComponent{    render() {return(           

welcome {this.props.username}        )    }}Welcome= wrapWithUsername(Welcome);exportdefaultWelcome;

此时,理解react-redux 的connect就好理解了

ConnectedComment = connect(mapStateToProps, mapDispatchToProps)(Component);// connect是一个返回函数的函数(就是个高阶函数)constenhance = connect(mapStateToProps, mapDispatchToProps);// 返回的函数就是一个高阶组件,该高阶组件返回一个与Redux store// 关联起来的新组件constConnectedComment = enhance(Component);

provider实现

importReactfrom'react'importReactDOMfrom'react-dom'import{ createStore, applyMiddleware, compose}from'redux'importthunkfrom'redux-thunk'import{ counter }from'./index.redux'// import { Provider } from 'react-redux'// 换成自己的Provider实现import{ Provider }from'./self-react-redux'importAppfrom'./App'conststore = createStore(counter, compose(  applyMiddleware(thunk),window.devToolsExtension ?window.devToolsExtension() :f=>f))ReactDOM.render(  (),document.getElementById('root'))

./self-react-redux

importReactfrom'react'importPropTypesfrom'prop-types'export function connect(){}classProviderextendsReact.Component{  static childContextTypes = {    store:PropTypes.object}  getChildContext() {return{ store:this.store }  }  constructor(props, context) {super(props, context)this.store = props.store  }  render(){returnthis.props.children  }}

connect实现

demo

importReactfrom'react'// import { connect } from 'react-redux'import{ connect }from'./self-react-redux'import{ addGun, removeGun, addGunAsync }from'./index.redux'@connect(// 你要state什么属性放到props里state=>({num:state.counter}),// 你要什么方法,放到props里,自动dispatch{ addGun, removeGun, addGunAsync })classAppextendsReact.Component{    render(){return(

现在有机枪{this.props.num}把

申请武器上交武器拖两天再给)    }}exportdefaultApp

./self-react-redux.js

// 高阶组件的写法exportfunctionconnect(maoStateToProps, mapStateToProps){returnfunction(WrapComponent){returnclassConnectComponentextendsReact.Component{    }  }}importReactfrom'react'importPropTypesfrom'prop-types'import{ bindActionCreator }from'./self-redux'// 使用简写形式// connect负责链接组件,给到redux里的数据放在组件的属性里// 1. 负责接收一个组件,把state里的一些数据放进去,返回一个组件// 2. 数据变化的时候,能通知组件exportconstconnect = (  mapStateToProps =state=>state,  mapDispatchToProps ={}) =>(WrapComponent) =>{returnclassConnectComponentextendsReact.Component{staticcontextTypes = {store: PropTypes.object    }constructor(props, context){super(props, context)this.state = {props: {}      }    }// 2 实现了mapStateToPropscomponentDidMount() {const{ store } =this.context      store.subscribe(()=>this.update())this.update()    }    update() {const{ store } =this.context// store.getState()这就是为什么mapStateToProps函数里面能拿到state conststateProps = mapStateToProps(store.getState())// 方法不能直接给,因为需要dispatch/**

          function addGun() {

            return { type: ADD_GUN }

          }

          直接执行addGun() 毫无意义

          要 addGun = () => store.dispatch(addGun()) 才有意义,其实就是把actionCreator包了一层

          bindActionCreators在手写redux api实现了

        */constdispatchProps = bindActionCreators(mapDispatchToProps, store.dispatch)// 注意state的顺序问题会覆盖this.setState({props: {          ...this.state.props,          ...stateProps,          ...dispatchProps,        }      })    }// 1render() {return}  }}

./self-redux.js

// creators: {addGun, removeGun, addGunAsync}// creators[v]:addGun(参数)// 返回:(参数) => dispatch(addGun(参数))functionbindActionCreator(creator, dispatch){return(...args) =>dispatch(creator(...args)) }exportfunctionbindActionCreators(creators, dispatch){letbound = {}Object.keys(creators).forEach(v=>{letcreator = creators[v]    bound[v] = bindActionCreator(creator, dispatch)  })returnbound }// 简写exportfunctionbindActionCreators(creators, dispatch){returnObject.keys(creators).reduce((ret, item) =>{    ret[item] =  bindActionCreator(creators[item], dispatch)returnret  }, {}) }

上一篇下一篇

猜你喜欢

热点阅读