Redux架構設計融合
阿新 • • 發佈:2018-12-19
在學習
react
的路上不斷前行,遇到了各式各樣的框架及架構,但整體是要做一個相容性及效能非常好的專案並非易事,在react
中,出現了redux
生態圈,得以將react
這匹黑馬駕馭得更好,此文將演示redux
生態在實際專案運用。
整備
網路:axios
一個基於promise
實現的網路請求庫,功能齊全,庫精簡
解放switch
,程式碼更簡潔
優化reduce
與渲染
可將複雜的業務邏輯非同步化
將整個store
樹持久化,解放各類儲存資料
在追過藝術道路上的UI
佈道者
結構
. ├── package-lock.json ├── package.json ├── public │ ├── favicon.ico │ ├── ico │ │ ├── favicon.icns │ │ ├── favicon.ico │ │ └── favicon.png │ └── index.html ├── src │ ├── components │ │ └── app.js │ ├── config.json │ ├── epics │ │ ├── app.js │ │ └── index.js │ ├── index.js │ ├── middles │ │ ├── index.js │ │ ├── log.js │ │ └── warn.js │ ├── reducers │ │ ├── app.js │ │ └── index.js │ ├── rx │ │ └── extends.js │ ├── selectors │ │ └── counter.js │ └── store │ └── persistor.js └── yarn.lock
目錄 | 說明 |
---|---|
src/components | 存放頁面元件 |
epics | 非同步請求或邏輯 |
middles | 各類中介軟體 |
reducers | redux core |
rx | rxjs 擴充套件方法 |
selectors | 渲染快取或多redux共享資料 |
store | 整合專用 |
- 專案會從src/index.js入口開始載入
- redux的store也是從這裡開始初始化
- src/store/persistor.js
這裡的persistor我們配置非常簡單,因為我們把一些配置交給了reducers
,middles
,epics
的index.js
去自動配置了
import {composeWithDevTools} from 'redux-devtools-extension'; # 1. 這裡使用引入redux-devtools開發者工具,用於觀察action與state樹的資訊 const epicMiddleware = createEpicMiddleware(); # 2. 例項化一個epic異常流框架 const rootEpic = combineEpics( ...epics ); # 3. 接著把我們`src/epics`目錄下的所有元件組合起來 let store = createStore( persistedReducer, preloadedState, comp(applyMiddleware(epicMiddleware, ...middles)) ); # 4. redux的store初始化,包括各類中介軟體 epicMiddleware.run(rootEpic); # 5. 別忘了執行異常流處理(之前版本不用手動流行,新版本必需)
- src/reducers/index.js
import {enableBatching} from 'redux-batched-actions';
# 這裡引入批actions,可以同時傳送多個action,實際業務中會用到很多
import {combineReducers} from "redux";
import appReducer from "./app";
export default enableBatching(combineReducers({
...appReducer,
}));
- src/reducers/app.js
import {createActions, handleActions} from 'redux-actions'; # 去除switch,簡潔我們的程式碼,注重程式碼視覺化 import {filterActions} from 'redux-ignore'; # 增加效能,屬於自己的功能自己的處理 export const actions = createActions({ changeText: (text) => ({text}), searchSuccess: (data) => ({data}), searchFailed: (error) => ({error}), }); export const types = { changeText: 'changeText', search: 'search', searchSuccess: 'searchSuccess', searchFailed: 'searchFailed', }; const defaultState = { name: '', searching: false, list: [] }; const reducer = handleActions({ changeText: (state, action) => ({...state, searching: true, name: action.payload.text}), searchSuccess: function (state, action) { return {...state, list: action.payload.data.items, searching: false}; }, searchFailed: function (state, action) { return {...state, searching: false}; }, }, defaultState); export default { app: filterActions(reducer, Object.keys(actions)) };
- src/epics/app.js
import 'rxjs/Rx';
import '../rx/extends';
import axios from 'axios';
import {Observable} from 'rxjs/Rx';
import {types, actions} from "../reducers/app";
export const apis = {
searchApi:(name)=>axios.get(`https://api.github.com/search/users?q=${name}`)
};
const search = action$ =>
action$.ofType(types.changeText)
.debounceTime(1000) //去抖動
.switchMap(action => Observable.fromPromise(apis.searchApi(action.payload.text)))
.retryWithDelay(3, 2000)//網路重試
.map(response => actions.searchSuccess(response.data))
.catch(error => Observable.of(actions.searchFailed(error)));
export default [search];
- src/middles/index.js
import {batchDispatchMiddleware} from 'redux-batched-actions';
import warn from './warn';
import log from './log';
# 可以引入自己的開發中間件
export default [
batchDispatchMiddleware,
warn,
log
]
- src/selectors/counter.js
import {createSelector} from 'reselect';
# 可以用於共享多個redux的資料,在components元件中引入即可,帶快取功能,增加渲染效能
const todosSelector = (state, props) => state.yeah;
# 所有帶計算功能的這將放入這裡
const fSelector = createSelector(
[todosSelector],
(todos) => {
return {
count:Math.abs(1,2),//這裡簡單列出個別函式,一般用於大量判斷條件,比對,複製類的
...todos
}
}
);
export default fSelector;
專案開發
npm start
演示效果
這裡使用github的api搜尋使用者資訊,在1秒內多次輸入只會以最後一次為準,經典的去抖搜尋方式