Last active
January 7, 2019 01:58
-
-
Save ywwwtseng/df7f5c1d4a4bf6fe03974d655ad6770c to your computer and use it in GitHub Desktop.
Simple redux tutorial
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 以下用簡單的程式碼說明 Redux | |
/* | |
* 核心概念 | |
* | |
* 1. 只使用一個 store 將整個應用程式的狀態 (state) 用物件樹 (object tree) 的方式儲存起來。 | |
* | |
* 2. 唯一可以改變這個 state 的方法就是發送 action,這個 action 其實就只是一個物件告訴 state 該怎麼改變而已。 | |
* | |
* 3. 實際因應 action 裡的內容對 state 做變化的函式叫做 reducer。 | |
* | |
*/ | |
// 建立 Store 的 function。 | |
function createStore(reducer, preloadedState) { | |
// 整個應用程式的狀態 | |
let state = preloadedState || {}; | |
// 提供 getState 方法去取得整個應用程式的狀態。 | |
const getState = function () { | |
return state; | |
}; | |
// 提供 dispatch 方法改變整個應用程式的狀態。 | |
const dispatch = function (action) { | |
console.log('\x1b[36m%s\x1b[0m', 'prev state:', state); | |
console.log('\x1b[33m%s\x1b[0m', 'action type:', action.type); | |
// 賦予 reducer 因應 action 裡的內容對 state 做變化,並更新 state。 | |
state = reducer(state, action); | |
console.log('next state:', state); | |
}; | |
dispatch({ type: 'REDUX@INIT' }); | |
return { | |
getState, | |
dispatch | |
}; | |
} | |
// reducer: 實際因應 action 裡的內容對 state 做變化。 | |
function reducer(state, action) { | |
switch (action.type) { | |
// 當 action type 是 'SET_LOCALE',增加或改變整個應用程式的狀態的 locale 的內容。 | |
case 'SET_LOCALE': | |
return Object.assign({}, state, { locale: action.payload }); | |
// 當 action type 是 'ADD_NEW_DATA',增加或改變整個應用程式的狀態的 data 的內容。 | |
case 'ADD_NEW_DATA': | |
return Object.assign({}, state, { data: action.payload }); | |
// 回傳當前整個應用程式的狀態。 | |
default: | |
return state; | |
} | |
} | |
// action creator: 產生 action,reducer 會因應 action 的內容對 state 做變化。 | |
function addNewData() { | |
return { | |
type: 'ADD_NEW_DATA', | |
payload: 'new data' | |
} | |
} | |
/* 建立 Redux 並與 React 結合 */ | |
// 建立 store | |
const store = createStore(reducer); | |
// 可以在建立 store 後,設定多語系,這裡簡單設定。 | |
store.dispatch({ type: 'SET_LOCALE', payload: 'zh-TW' }); | |
/* | |
* 建立 React element,我們先以一個 obj 來代表。 | |
* 實際上它俱備很多屬性。 | |
* 解釋 redux 我們只會探討 React element 中的 props 屬性和 context 屬性。 | |
* | |
*/ | |
let ReactEl = { props: {}, context: {} }; | |
// react 有提供某個 API 可以將資料提供給整個應用程式 React element 的 context 屬性。 | |
// 我們以簡單的方法模擬。 | |
function Provider(store, ReactEl) { | |
ReactEl.context.store = store; | |
} | |
// 將 store 與連接的 React element 整理成較方便使用。 | |
function connect(mapStateToProps, actions) { | |
// 當執行 action 必須使用 store.dispatch 執行它,以下做一些處理。 | |
const setDispatchToAllActions = {}; | |
let key; | |
for(key in actions) { | |
if (actions.hasOwnProperty(key)) { | |
setDispatchToAllActions[key] = (function () { | |
ReactEl.context.store.dispatch(actions[key]()); | |
// 執行 action 跟新 React element 的 props。 | |
Object.assign( | |
ReactEl.props, | |
mapStateToProps(ReactEl.context.store.getState()), | |
setDispatchToAllActions | |
); | |
}); | |
} | |
} | |
return function (ReactEl) { | |
// 將經由 mapStateToProps 整理後的 state,與賦予 dispatch 後的 actions,傳入 React element 的 props。 | |
Object.assign( | |
ReactEl.props, | |
mapStateToProps(ReactEl.context.store.getState()), | |
setDispatchToAllActions | |
); | |
return ReactEl; | |
} | |
} | |
// 將 store 提供給整個應用程式 React element。 | |
Provider(store, ReactEl); | |
// 將 store 與連接的 React element 整理成較方便使用。 | |
// 這個 View 與 state.data 的資料連接,那 mapStateToProps 可以寫成 state => ({ data: state.data })。 | |
ReactEl = connect(state => ({ data: state.data }), { addNewData })(ReactEl); | |
// 在這 View 中我們執行 addNewData。 | |
ReactEl.props.addNewData(); | |
// 當這個 React element 的 props 改變,React 就會跟新這個 React element。 | |
console.log('Update React Element', ReactEl.props); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment