隨着
JavaScript
單頁應用開發日趨複雜,管理不斷變化的state
變得十分困難html
state
被儲存在一棵object tree
中,而且這個object tree
只存在於惟一的store
中state
state
的方法就是觸發action
reducer
函數執行修改
action
來通知reducer
函數來執行相應修改state
動做store
,裏面保存一棵狀態樹state tree
dispatch
行爲action
給store
,而不是直接通知其它組件store
中的state
來刷新本身的視圖
本文以一個小計數器爲例子逐一講解redux
<body>
<div id="counter">
<div id="counter-value"></div>
<button id="increment-btn">+</button>
<button id="decrement-btn">-</button>
</div>
</body>
複製代碼
action
動做const INCREMENT = Symbol.for('INCREMENT');
const DECREMENT = Symbol.for('DECREMENT');
複製代碼
reducer
函數,用來管理狀態function reducer(state, action) {
switch (action.type) {
case INCREMENT:
return state + 1; // 返回一個加1的新狀態
case DECREMENT:
return state - 1;// 返回一個減1的新狀態
default:
return state;
}
}
複製代碼
store
import {createStore} from 'redux';
let store = createStore(reducer,initState);
複製代碼
let counterValue = document.getElementById('counter-value');
let incrementBtn = document.getElementById('increment-btn');
let decrementBtn = document.getElementById('decrement-btn');
function render() {
counterValue.innerHTML = store.getState();
}
render();
let unsubscribe = store.subscribe(render);
複製代碼
incrementBtn.addEventListener('click',function () {
store.dispatch({
type:INCREMENT
})
})
decrementBtn.addEventListener('click',function () {
store.dispatch({
type:DECREMENT
})
})
複製代碼
setTimeout(()=>{
unsubscribe()
},3000)
複製代碼
React
版action
動做const INCREMENT = Symbol.for('INCREMENT');
const DECREMENT = Symbol.for('DECREMENT');
複製代碼
reducer
函數,用來管理狀態function reducer(state, action) {
switch (action.type) {
case INCREMENT:
return state + 1; // 返回一個加1的新狀態
case DECREMENT:
return state - 1;// 返回一個減1的新狀態
default:
return state;
}
}
- 【3】建立倉庫`store`
```JS import {createStore} from 'redux'; let store = createStore(reducer,initState); 複製代碼
action
指派對象const boundActions = bindActionCreators(actions,store.dispatch)
複製代碼
export default class Counter extends Component {
state = {number:store.getState()}
componentDidMount(){
this.unsubscribe=store.subscribe(()=>{
this.setState({
number:store.getState()
})
})
}
componentWillUnmount(){
this.unsubscribe()
}
render() {
return (
<> <p>{this.state.number}</p> <button onClick={boundActions.increment}>+</button> <button onClick={boundActions.decrement}>-</button> </> ) } } 複製代碼
createStore
reducer
,初始狀態preloadedState
getState
subscribe
dispatch
function createStore(reducer,preloadedState){
let currentReducer = reducer;
let currentState = preloadedState;
let currentListeners = [];
function getState(){
return currentState;
}
function dispatch(action){
if(!isPlainObject(action)){
throw new Error('action必須是一個純對象');
}
if(typeof action.type === 'undefined'){
throw new Error('action必須有type屬性')
}
currentState = currentReducer(currentState,action);
for(let i = 0;i<currentListeners.length;i++){
const listener = currentListeners[i];
currentListener();
}
return action;
}
function subscribe(listener){
currentListeners.push(listener);
return function(){
const index = currentListeners.indexOf(listener);
currentListeners.splice(index,1);
}
}
return {
getState,
dispatch,
subscribe
}
}
複製代碼
bindActionCreators
actionCreators
,dispatch
function bindActionCreators(actionCreators,dispatch){
if(typeof actionCreators === 'function'){
return bindActionCreator(actionCreators,dispatch);
}
const boundActionCreators = {};
for(let key in actionCreators){
if(actionCreators.hasOwnProperty(key)){
boundActionCreators[key] = bindActionCreator(actionCreators[key],dispatch);
}
}
return boundActionCreators;
}
fucntion bindActionCreator(actionCreator,dispatch){
return function(){
return dispatch(actionCreator.apply(this,arguments));
}
}
複製代碼
combineReducers
reducers
對象reducers
函數function combineReducers(reducers){
const reducerKeys = Object.keys(reducers);
return function(state={},action){
const nextState = {};
for(let i = 0;i<reducerKeys.length;i++){
const reducer = reducers[key];
const previousStateForkey = state[key];
const nextStateForkey = reducer(previousStateForkey,action);
nextState[key] = nextStateForkey;
}
return nextState;
}
}
複製代碼