在介绍 createStore
方法原理以前,先回顾一下 redux 的使用过程,而后再根据使用的方式编写源码。react
import { createStore } from 'redux'
import reducer from './reducer'
const store = createStore(reducer)
export default store
复制代码
使用 redux 经过 createStore
建立容器,须要传入一个函数 reducer
称为处理器,这个函数定义怎样修改容器里面的状态。redux
const initState = { number: 0 }
function reducer(state = initState, action) {
switch (action.type) {
case 'INCREMENT':
return { number: state.number + 1 }
case 'DECREMENT':
return { number: state.number - 1 }
default:
return state
}
}
export default reducer
复制代码
处理器函数第一个参数是要管理的状态,第二个参数是动做对象,那么接下来咱们开始定义这个动做对象。函数
const actions = {
increment () {
return {type: 'INCREMENT'}
},
decrement () {
return {type: 'DECREMENT'}
}
}
export default actions
复制代码
actions
能够写成对象和函数的形式,若是写成对象,那么对象中的每一项必须是函数。函数的返回值是对象,并且对象必需要有type
属性。关于actions
为何要这样写了,目的是能够提供给 bindActionCreators
函数使用。ui
function bindActionCreator(actionCreator, dispatch) {
return (...args) => dispatch(actionCreator(...args))
}
export default function bindActionCreators(actionCreators, dispatch) {
if (typeof actionCreators === 'function') {
return bindActionCreator(actionCreators, dispatch)
}
if (typeof actionCreators !== 'object' || actionCreators === null) {
throw new Error('actionCreators是对象或函数')
}
const keys = Object.keys(actionCreators)
const boundActionCreators = {}
for (let i = 0; i < keys.length; i++) {
const key = keys[i]
const actionCreator = actionCreators[key]
if (typeof actionCreator === 'function') {
boundActionCreators[key] = bindActionCreator(actionCreator, dispatch)
}
}
return boundActionCreators
}
复制代码
如今一切准备就绪,在组件中开始使用管理的状态,须要导入咱们建立的 store
容器和定义的 actions
动做,这里并无使用 react-redux,目的是为了演示 redux 的原始方法用法,为了更好的理解状态的更改的过程。this
import store from './store'
import actions from './store/actions'
class App extends Component {
constructor(props) {
super(props);
this.state = {
number: 0
}
}
componentDidMount() {
this.unsubscribe = store.subscribe(() => {
this.setState({number: store.getState().number})
})
}
componentWillUnmount () {
this.unsubscribe()
}
handleClick = () => {
store.dispatch(actions.increment())
}
render() {
return (
<div> <p>{this.state.number}</p> <button onClick={this.handleClick}>+</button> </div>
);
}
}
复制代码
上面代码就是一个计数器组件,经过点击加号,会触发一个点击事件,点击事件会调用 dispatch
方法,传入参数是actions
定义的动做类型,并且经过生命周期在组件挂载完成的在 subscribe
订阅了更新状态的方法,这样每次才能触发视图更新。spa
如今已经把 redux 的基本使用介绍完成,下面是实现内部的方法。code
export const ActionTypes = {
INIT: '@@redux/INIT'
}
export default function createStore(reducer, preloadedState) {
let currentReducer = reducer
let currentState = preloadedState
let currentListeners = []
let nextListeners = currentListeners
let isDispatching = false
function getState() {
return currentState
}
function subscribe(listener) {
let isSubscribed = true
nextListeners.push(listener)
return function unsubscribe() {
if (!isSubscribed) {
return
}
isSubscribed = false
const index = nextListeners.indexOf(listener)
nextListeners.splice(index, 1)
}
}
function dispatch(action) {
if (isDispatching) {
throw new Error('reducer函数中不能调用dispatch')
}
try {
isDispatching = true
currentState = currentReducer(currentState, action)
} finally {
isDispatching = false
}
const listeners = currentListeners = nextListeners
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i]
listener()
}
return action
}
dispatch({ type: ActionTypes.INIT })
return {
dispatch,
subscribe,
getState
}
}
复制代码
currentState
是容器的状态,在容器的建立时指定第二个参是默认状态,每次调用 dispatch
会触发更改状态的处理器函数 currentReducer
获得新的状态,而后会触发订阅更新视图的方法 listener
函数。component