動手實現 React-redux(三) Provider
阿新 • • 發佈:2018-12-14
react-redux.js:
import React, { Component } from 'react' import PropTypes from 'prop-types' export const connect = (mapStateToProps, mapDispatchToProps) => (WrappedComponent) => { class Connect extends Component { static contextTypes = { store: PropTypes.object } constructor () { super() this.state = { allProps: {} } } componentWillMount () { const { store } = this.context this._updateProps() store.subscribe(() => this._updateProps()) } _updateProps () { const { store } = this.context let stateProps = mapStateToProps ? mapStateToProps(store.getState(), this.props) : {} // 防止 mapStateToProps 沒有傳入 let dispatchProps = mapDispatchToProps ? mapDispatchToProps(store.dispatch, this.props) : {} // 防止 mapDispatchToProps 沒有傳入 this.setState({ allProps: { ...stateProps, ...dispatchProps, ...this.props } }) } render () { return <WrappedComponent {...this.state.allProps} /> } } return Connect } export class Provider extends Component { static propTypes = { store: PropTypes.object, children: PropTypes.any } static childContextTypes = { store: PropTypes.object } getChildContext () { return { store: this.props.store } } render () { return ( <div>{this.props.children}</div> ) } }
App.js:
import React, { Component } from 'react'; import PropTypes from 'prop-types' import Header from './Header' import { Provider } from './react-redux' function createStore (reducer) { let state = null const listeners = [] const subscribe = (listener) => listeners.push(listener) const getState = () => state const dispatch = (action) => { state = reducer(state, action) listeners.forEach((listener) => listener()) } dispatch({}) // 初始化 state return { getState, dispatch, subscribe } } const themeReducer = (state, action) => { if (!state) return { themeColor: 'red' } switch (action.type) { case 'CHANGE_COLOR': return { ...state, themeColor: action.themeColor } default: return state } } const store = createStore(themeReducer) class App extends Component { render() { return ( <Provider store={store}> <Header /> </Provider> ); } } export default App;