在介紹 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