react深入 - 手写实现react-redux api
简介:简单实现react-redux基础api react-redux api回顾<Provider store> 使组件层级中的 connect() 方法都能够获得 Redux store 根组件应该嵌套在 <Provider> 中 ReactDOM.render( <Provider store={store}> <MyRootComponent /> </Provider>,rootEl ) ReactDOM.render( <Provider store={store}> <Router history={history}> <Route path="/" component={App}> <Route path="foo" component={Foo}/> <Route path="bar" component={Bar}/> </Route> </Router> </Provider>,document.getElementById('root') ) connect([mapStateToProps],[mapDispatchToProps],[mergeProps],[options]) [mapStateToProps(state,[ownProps]): stateProps] (Function) 如果定义该参数,组件将会监听 Redux store 的变化。任何时候,只要 Redux store 发生改变,mapStateToProps 函数就会被调用。该回调函数必须返回一个纯对象,这个对象会与组件的 props 合并 如果你省略了这个参数,你的组件将不会监听 Redux store const mapStateToProps = (state,ownProps) => { return { active: ownProps.filter === state.visibilityFilter } } [mapDispatchToProps(dispatch,[ownProps]): dispatchProps] (Object or Function) Object: 它的每个键名也是对应 UI 组件的同名参数,键值应该是一个函数(action creator),会被当作 Action creator ,返回的 Action 会由 Redux 自动发出,Function: 会得到dispatch和ownProps(容器组件的props对象)两个参数(此时可能用到Redux 的辅助函数 bindActionCreators()) 省略这个 mapDispatchToProps 参数,默认情况下,dispatch 会注入到你的组件 props 中,你可以this.props.dispatch调用 eg: connect(mapStateToProps,{ hideAdPanel,pushAdData,})(AdPanel) function mapDispatchToProps(dispatch) { return { todoActions: bindActionCreators(todoActionCreators,dispatch),counterActions: bindActionCreators(counterActionCreators,dispatch) } } 知识点补充 - React高阶组件(Higher-Order Components)高阶组件就是一个函数,且该函数接受一个组件作为参数,并返回一个新的组件 使用场景:两个组件大部分代码都是重复的+且更好的封闭性,不需要关注数据的获取 import React,{Component} from 'react' class Welcome extends Component { constructor(props) { super(props); this.state = { username: '' } } componentWillMount() { let username = localStorage.getItem('username'); this.setState({ username: username }) } render() { return ( <div>welcome {this.state.username}</div> ) } } export default Welcome; import React,{Component} from 'react' class Goodbye extends Component { constructor(props) { super(props); this.state = { username: '' } } componentWillMount() { let username = localStorage.getItem('username'); this.setState({ username: username }) } render() { return ( <div>goodbye {this.state.username}</div> ) } } export default Goodbye; welcome和goodbye组件相似,只能获取的数据不一样,用高阶组件,提取公共部分 import React,{Component} from 'react' export default (WrappedComponent) => { class NewComponent extends Component { constructor() { super(); this.state = { username: '' } } componentWillMount() { let username = localStorage.getItem('username'); this.setState({ username: username }) } render() { return <WrappedComponent username={this.state.username}/> } } return NewComponent } 简化welcome和goodbye import React,{Component} from 'react'; import wrapWithUsername from 'wrapWithUsername'; class Welcome extends Component { render() { return ( <div>welcome {this.props.username}</div> ) } } Welcome = wrapWithUsername(Welcome); export default Welcome; 此时,理解react-redux 的connect就好理解了 ConnectedComment = connect(mapStateToProps,mapDispatchToProps)(Component); // connect是一个返回函数的函数(就是个高阶函数) const enhance = connect(mapStateToProps,mapDispatchToProps); // 返回的函数就是一个高阶组件,该高阶组件返回一个与Redux store // 关联起来的新组件 const ConnectedComment = enhance(Component); provider实现import React from 'react' import ReactDOM from 'react-dom' import { createStore,applyMiddleware,compose} from 'redux' import thunk from 'redux-thunk' import { counter } from './index.redux' // import { Provider } from 'react-redux' // 换成自己的Provider实现 import { Provider } from './self-react-redux' import App from './App' const store = createStore(counter,compose( applyMiddleware(thunk),window.devToolsExtension ? window.devToolsExtension() : f => f )) ReactDOM.render( ( <Provider store={store}> <App /> </Provider> ),document.getElementById('root')) ./self-react-redux import React from 'react' import PropTypes from 'prop-types' export function connect(){ } class Provider extends React.Component{ static childContextTypes = { store: PropTypes.object } getChildContext() { return { store: this.store } } constructor(props,context) { super(props,context) this.store = props.store } render(){ return this.props.children } } connect实现demo import React from '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,addGunAsync } ) class App extends React.Component{ render(){ return ( <div> <h1>现在有机枪{this.props.num}把</h1> <button onClick={this.props.addGun}>申请武器</button> <button onClick={this.props.removeGun}>上交武器</button> <button onClick={this.props.addGunAsync}>拖两天再给</button> </div> ) } } export default App ./self-react-redux.js // 高阶组件的写法 export function connect(maoStateToProps,mapStateToProps) { return function(WrapComponent) { return class ConnectComponent extends React.Component{ } } } import React from 'react' import PropTypes from 'prop-types' import { bindActionCreator } from './self-redux' // 使用简写形式 // connect负责链接组件,给到redux里的数据放在组件的属性里 // 1. 负责接收一个组件,把state里的一些数据放进去,返回一个组件 // 2. 数据变化的时候,能通知组件 export const connect = ( mapStateToProps = state => state,mapDispatchToProps ={} ) => (WrapComponent) => { return class ConnectComponent extends React.Component { static contextTypes = { store: PropTypes.object } constructor(props,context){ super(props,context) this.state = { props: {} } } // 2 实现了mapStateToProps componentDidMount() { const { store } = this.context store.subscribe(() => this.update()) this.update() } update() { const { store } = this.context // store.getState()这就是为什么mapStateToProps函数里面能拿到state const stateProps = mapStateToProps(store.getState()) // 方法不能直接给,因为需要dispatch /** function addGun() { return { type: ADD_GUN } } 直接执行addGun() 毫无意义 要 addGun = () => store.dispatch(addGun()) 才有意义,其实就是把actionCreator包了一层 bindActionCreators在手写redux api实现了 */ const dispatchProps = bindActionCreators(mapDispatchToProps,store.dispatch) // 注意state的顺序问题会覆盖 this.setState({ props: { ...this.state.props,...stateProps,...dispatchProps,} }) } // 1 render() { return <WrapComponent {...this.state.props}></WrapComponent> } } } ./self-redux.js // creators: {addGun,addGunAsync} // creators[v]:addGun(参数) // 返回:(参数) => dispatch(addGun(参数)) function bindActionCreator(creator,dispatch) { return (...args) => dispatch(creator(...args)) } export function bindActionCreators(creators,dispatch) { let bound = {} Object.keys(creators).forEach( v => { let creator = creators[v] bound[v] = bindActionCreator(creator,dispatch) }) return bound } // 简写 export function bindActionCreators(creators,dispatch) { return Object.keys(creators).reduce((ret,item) => { ret[item] = bindActionCreator(creators[item],dispatch) return ret },{}) } 原文地址:https://segmentfault.com/a/1190000016759675 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |