Skip to content

Instantly share code, notes, and snippets.

@ywwwtseng
Last active January 7, 2019 01:58
Show Gist options
  • Save ywwwtseng/df7f5c1d4a4bf6fe03974d655ad6770c to your computer and use it in GitHub Desktop.
Save ywwwtseng/df7f5c1d4a4bf6fe03974d655ad6770c to your computer and use it in GitHub Desktop.
Simple redux tutorial
// 以下用簡單的程式碼說明 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