React - Redux架构设计融合

作者: 大猪大猪 | 来源:发表于2018-11-03 21:44 被阅读19次

    我们在学习react的路上不断前行,遇到了各式各样的框架及架构,但整体是要做一个兼容性及性能非常好的项目并非易事,在react中,出现了redux生态圈,得以将react这匹黑马驾驭得更好,此文将演示redux生态在实际项目运用。


    整备

    网络:axios
    一个基于promise实现的网络请求库,功能齐全,库精简
    融合:redux-actions
    解放switch,代码更简洁
    性能:redux-ignorereselect
    优化reduce与渲染
    数据流:redux-observable
    可将复杂的业务逻辑异步化
    持久化:redux-persist
    将整个store树持久化,解放各类保存数据
    界面:material-ui
    在追过艺术道路上的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 整合专用
    1. 项目会从src/index.js入口开始加载
    2. redux的store也是从这里开始初始化
    3. src/store/persistor.js
      这里的persistor我们配置非常简单,因为我们把一些配置交给了reducers,middles,epicsindex.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. 别忘了运行异常流处理(之前版本不用手动流行,新版本必需)
    
    1. 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,
    }));
    
    1. 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))
    };
    
    1. 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];
    
    1. src/middles/index.js
    import {batchDispatchMiddleware} from 'redux-batched-actions';
    import warn from './warn';
    import log from './log';
    # 可以引入自己的开发中间件
    export default [
        batchDispatchMiddleware,
        warn,
        log
    ]
    
    1. 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秒内多次输入只会以最后一次为准,经典的去抖搜索方式


    Welcome get me a start react-redux-template

    相关文章

      网友评论

        本文标题:React - Redux架构设计融合

        本文链接:https://www.haomeiwen.com/subject/ofllxqtx.html