【Javascript】实现一个简易版react-redux
AwesomeDevin opened this issue · comments
index.js (createStore)
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'
import { Provider } from './connect'
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 Index extends Component {
// static childContextTypes = {
// store: PropTypes.object
// }
// getChildContext () {
// return { store }
// }
render () {
return (
<div>
<Header />
<Content />
</div>
)
}
}
ReactDOM.render(
<Provider store={store}>
<Index />
</Provider>,
document.getElementById('title')
)
connect.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 () {
const { store } = this.context
let stateProps = mapStateToProps(store.getState())
// {...stateProps} 意思是把这个对象里面的属性全部通过 `props` 方式传递进去
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>
)
}
}
themeswitch.js
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { connect } from './connect'
class ThemeSwitch extends Component {
static contextTypes = {
store: PropTypes.object
}
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 })
// }
handleSwitchColor (color) {
const { store } = this.context
if (this.props.onSwitchColor) {
this.props.onSwitchColor(color)
}
}
render () {
return (
<div>
<button onClick={this.handleSwitchColor.bind(this, 'red')} style={{color:this.state.themeColor}}>Red</button>
<button onClick={this.handleSwitchColor.bind(this, 'blue')} >Blue</button>
</div>
)
}
}
const mapStateToProps = (state) => {
return {
themeColor: state.themeColor
}
}
const mapDispatchToProps = (dispatch) => {
return {
onSwitchColor: (color) => {
dispatch({ type: 'CHANGE_COLOR', themeColor: color })
}
}
}
ThemeSwitch = connect(mapStateToProps, mapDispatchToProps)(ThemeSwitch)
export default ThemeSwitch