看这里之前,需要了解redux最简易的版本实现代码的逻辑,这里我们粘贴一下,详细内容请移步redux原理 + 简易实现 —- 基础实现篇
**
function createStore (state, stateChanger) {
const listeners = []
const subscribe = (listener) => listeners.push(listener)
const getState = () => state
const 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 = 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)
...
定义了一个主题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>
)
}
}
接着,我们来看一下如何使用它
...
// 头部引入 Provider
import { Provider } from './react-redux'
...
// 删除 Index 里面所有关于 context 的代码
class Index extends Component {
render () {
return (
<div>
<Header />
<Content />
</div>
)
}
}
// 把 Provider 作为组件树的根节点
// 这里的store是指redux的createStore创建出来的store
ReactDOM.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.context
this._updateThemeColor()
store.subscribe(() => this._updateThemeColor())
}
_updateThemeColor () {
const { store } = this.context
const state = store.getState()
this.setState({ themeColor: state.themeColor })
}
// dispatch action 去改变颜色
handleSwitchColor (color) {
const { store } = this.context
store.dispatch({
type: 'CHANGE_COLOR',
themeColor: color
})
}
render () {
return (
<div>
<button
style={{ color: this.state.themeColor }}
onClick={this.handleSwitchColor.bind(this, 'red')}>Red</button>
<button
style={{ 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 } = context
this._updateThemeColor()
store.subscribe(() => _updateThemeColor())
}, [])
const _updateThemeColor = () => {
const { store } = context
const state = store.getState()
setState({ themeColor: state.themeColor })
}
// dispatch action 去改变颜色
const handleSwitchColor = (color) {
const { store } = context
store.dispatch({
type: 'CHANGE_COLOR',
themeColor: color
})
}
render () {
return (
<div>
<button
style={{ color: this.state.themeColor }}
onClick={handleSwitchColor('red')}>Red</button>
<button
style={{ color: this.state.themeColor }}
onClick={this.handleSwitchColor('blue')}>Blue</button>
</div>
)
}
}