看这里之前,需要了解redux最简易的版本实现代码的逻辑,这里我们粘贴一下,详细内容请移步redux原理 + 简易实现 —- 基础实现篇
**
function createStore (state, stateChanger) {const listeners = []const subscribe = (listener) => listeners.push(listener)const getState = () => stateconst dispatch = (action) => {state = stateChanger(state, action) // 覆盖原对象listeners.forEach((listener) => listener())}dispatch({})return { getState, dispatch, subscribe }}
结合我们要演示的reducer,代码如下
import React, { Component } from 'react'import PropTypes from 'prop-types'import ReactDOM from 'react-dom'import Header from './Header'import Content from './Content'import './index.css'function createStore (reducer) {let state = nullconst listeners = []const subscribe = (listener) => listeners.push(listener)const getState = () => stateconst dispatch = (action) => {state = reducer(state, action)listeners.forEach((listener) => listener())}dispatch({}) // 初始化 statereturn { 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)...
定义了一个主题redecer,并设置了对其操作是改变颜色
其实Provider逻辑很简单,就是把react的context传递给下面,也就是传递给connect组件,所以我们用一个HOC的方式来写
import React, { Component } from 'react'export const ThemeContext = React.createContext(props.store)export class Provider extends Component {constructor(props){super(props)}render () {return (<ThemeContext.Provider>{this.props.children}</ThemeContext.Provider>)}}
接着,我们来看一下如何使用它
...// 头部引入 Providerimport { Provider } from './react-redux'...// 删除 Index 里面所有关于 context 的代码class Index extends Component {render () {return (<div><Header /><Content /></div>)}}// 把 Provider 作为组件树的根节点// 这里的store是指redux的createStore创建出来的storeReactDOM.render(<Provider store={store}><Index /></Provider>,document.getElementById('root'))
我们来看看Provider底下的组件,如果没有connect组件的话,该如何调用呢
import { ThemeContext } from './Provider'class Index extends Component {static contextType = ThemeContext;constructor () {super()this.state = { themeColor: '' }}componentWillMount () {const { store } = this.contextthis._updateThemeColor()store.subscribe(() => this._updateThemeColor())}_updateThemeColor () {const { store } = this.contextconst state = store.getState()this.setState({ themeColor: state.themeColor })}// dispatch action 去改变颜色handleSwitchColor (color) {const { store } = this.contextstore.dispatch({type: 'CHANGE_COLOR',themeColor: color})}render () {return (<div><buttonstyle={{ color: this.state.themeColor }}onClick={this.handleSwitchColor.bind(this, 'red')}>Red</button><buttonstyle={{ color: this.state.themeColor }}onClick={this.handleSwitchColor.bind(this, 'blue')}>Blue</button></div>)}}
接下来,我们再看看如果用hooks如何实现,hooks主要的区别在于接受context的时候需要用到useContext这个API
import { ThemeContext } from './Provider'class Index = (props) => {const context = useContext(ThemeContext)const [ themeColor, setState ] = useState({ themeColor: '' })useEffetcs(()=> {const { store } = contextthis._updateThemeColor()store.subscribe(() => _updateThemeColor())}, [])const _updateThemeColor = () => {const { store } = contextconst state = store.getState()setState({ themeColor: state.themeColor })}// dispatch action 去改变颜色const handleSwitchColor = (color) {const { store } = contextstore.dispatch({type: 'CHANGE_COLOR',themeColor: color})}render () {return (<div><buttonstyle={{ color: this.state.themeColor }}onClick={handleSwitchColor('red')}>Red</button><buttonstyle={{ color: this.state.themeColor }}onClick={this.handleSwitchColor('blue')}>Blue</button></div>)}}
