why redux?
- 隨著 JavaScript 單頁應用開發日趨複雜,管理不斷變化的 state 非常困難
- Redux的出現就是為了解決state裡的資料問題
- 在React中,資料在元件中是單向流動的
- 資料從一個方向父元件流向子元件(通過props),由於這個特徵,兩個非父子關係的元件(或者稱作兄弟元件)之間的通訊比較麻煩
what is redux?
工作流
設計思想
- Redux是將整個應用狀態儲存到到一個地方,稱為store
- store裡面儲存一棵狀態樹(state tree)
- 元件可以派發(dispatch)行為(action)給store,而不是直接通知其它元件
- 其它元件可以通過訂閱store中的狀態(state)來重新整理自己的檢視.
三大原則
- 整個應用的 state 被儲存在一棵 object tree 中,並且這個 object tree 只存在於唯一一個 store 中 State 是隻讀的,惟一改變 state 的方法就是觸發 action,
- action是一個用於描述已發生事件的普通物件 使用純函式來執行修改,為了描述action如何改變state tree ,你需要編寫 reducers
- 單一資料來源的設計讓React的元件之間的通訊更加方便,同時也便於狀態的統一管理
how redux?
1.安裝
npm i redux -S
複製程式碼
2.簡單例子
1.引入
import {createStore} from 'redux';
//createStore 用來建立狀態倉庫
複製程式碼
2.建立state
let initState = {
title: 'star'
}
複製程式碼
3.建立reducer
const CHANGETITLE = 'CHANGETITLE'; //action-todos
function reducer(state= initState, action){
switch(action.type){
case CHANGETITLE:
return state.title = action.title;
}
}
複製程式碼
4.建立倉庫
let store = createStore(reducer);
複製程式碼
5.觸發dispatch中傳入action
store.dispatch({type: CHANGETITLE, title: 'xingxing'})
複製程式碼
完整程式碼
import {createStore} from 'redux';
const CHANGETITLE = 'CHANGETITLE';
function reducer(state= initState, action){
switch(action.type){
case CHANGETITLE:
state.title = action.title;
}
console.log(state);
}
let store = createStore(reducer);
store.subscribe(()=>{ //訂閱事件,在dispatch時觸發
console.log('render');
})
store.dispatch({type: CHANGETITLE, title: 'xingxing'})
複製程式碼
複雜些例子
在真實開發中需要開闢一個檔案空間來管理倉庫
- 檔案結構化
- 多reducer,合併reducer
1.actions
action-type.js
//action-type衡量,通過引入使用,減少拼寫錯誤引發的問題
export const INCREMENT = 'INCREMENT'
export const DECREMNET = 'DECREMNET'
複製程式碼
actions/count.js
import * as types from "../action-types"
//用於生成action
let counter = {
add(n){
return {type: types.INCREMENT, count: n}
}
}
export default counter
複製程式碼
2.reducers
reducers/count.js
import {INCREMENT,DECREMENT} from '../actions/action-type'
let initState = {
count: 0
}
function reducer(state = initState,action){
switch(action.type){
case INCREMENT:
state.count = state.count + action.number;
break;
case DECREMENT:
state.count = state.count - action.number;
break;
}
return state
}
export default reducer
複製程式碼
合併reducer
reducers/index.js
import todos from './todo';
import count from './count';
import {combineReducers} from 'redux'
let reducers = combineReducers({
todos,
count
})
export default reducers;
複製程式碼
store/index.js 初始化倉庫
import {INCEMENT,DECREMENT} from './actions/action-type';
import {createStore} from 'redux';
import reducers from './reducers'
export default createStore(reducers);
複製程式碼
how is redux work?
- redux的資料來源是建立reducer時,傳進去的initState。
- 為了避免state被隨意篡改,redux通過dispatch reducer來更改資料。
- redux可以通過subscribe訂閱狀態修改事件
//簡單實現
function createStore(reducer){
let state;
let listeners = [];
function subscribe(listener){
listeners.push(listener);
return ()=> listeners = listeners.filter(fn=>fn!==listener);
}
function dispatch(action){
listeners.forEach(listener=>listener());
reducer(state, action)
}
dispatch({})
function getState(){
return state;
}
return {subscribe, dispatch, getState}
}
複製程式碼
合併reducer
function combineReducers(reducers){
return (state={},action)=>{
let newState = {};
for(let key in reducers){
let s = reducers[key](state[key],action);
newState[key] = s;
}
return newState;
}
}
複製程式碼
完整程式碼
function createStore(reducer){
let state;
let listeners = [];
function subscribe(listener){
listeners.push(listener);
return ()=>{
listeners = listeners.filter(l=> l!==listener)
}
}
dispatch({})
function dispatch(action){
state = reducer(state,action);
listeners.forEach(l=>l());
}
function getState(){
return state;
}
return {subscribe,dispatch,getState};
}
function combineReducers(reducers){
return (state={},action)=>{
let newState = {};
for(let key in reducers){
let s = reducers[key](state[key],action);
newState[key] = s;
}
return newState;
}
}
export {createStore,combineReducers}
複製程式碼
最近在研究redux,歡迎指出問題。後續更新react-redux全家桶系列研究