美文网首页
Redux实现状态管理的小demo

Redux实现状态管理的小demo

作者: 华戈的小书 | 来源:发表于2019-04-08 18:22 被阅读0次

    此项目是用Create React App启动的.

    可用脚本

    在项目目录中,可以运行:

    npm start

    以开发模式运行应用程序。

    打开http://localhost:3000在浏览器中查看。

    如果进行编辑,页面将重新加载。

    您还将在控制台中看到任何eslint错误。

    项目目录结构

    |-- package.json
    |-- public
    |   |-- favicon.ico
    |   |-- index.html
    |   `-- manifest.json
    |-- src
    |   |-- components  // 封装组件
    |   |   `-- Button.js
    |   |-- modals  // 存放不同的action
    |   |   |-- reducerCaption.js
    |   |   `-- reducerFontSize.js
    |   |-- routes  // 视图展示层
    |   |   |-- App.js
    |   |   |-- Counter.js
    |   |   |-- FontSize.js
    |   |   `-- Summary.js
    |   |-- index.css
    |   |-- index.js
    |   |-- App.test.js
    |   |-- serviceWorker.js
    |   `-- store.js  // store仓库
    |-- README.md
    |-- .gitignore
    `-- yarn.lock
    

    demo示例功能点

    • 使用Redux进行状态管理;
    • 使用combineReducers将多个reducer组合管理。

    代码地址:

    https://github.com/Zhonghua926/demo-redux master分支

    功能实现

    • 1.安装create-react-app
    npm install -g create-react-app
    
    • 2.查看版本
    create-react-app --version
    // 我的版本是2.1.1
    
    • 3.通过命令创建一个demo文件
    create-react-app demo
    
    • 4.删除App.js,App.css,然后
    // 新建文件
    |-- |-- components  // 封装组件
    |   |   `-- Button.js
    |   |-- modals  // 存放不同的action
    |   |   |-- reducerCaption.js
    |   |   `-- reducerFontSize.js
    |   `-- routes  // 视图展示层
    |       |-- App.js
    |       |-- Counter.js
    |       |-- FontSize.js
    |       `-- Summary.js
    `-- store.js  // store仓库
    
    // 修改App.test.js
    import App from './App';  -- >  import App from './routes/App';
    
    • 5.存放公用的state,以及对于这个state的一系列操作。
    // reducerCaption.js
    // type类型
    const INCREMENT = 'increment';
    const DECREMENT = 'decrement';
     // 初始化state数据
    const initValues = {
        'First': 0,
        'Second': 10,
        'Third': 20,
    }
    // action行为
    export const increment = (counterCaption) => {
        return {
            type: INCREMENT,
            counterCaption,
        }
    }
    export const decrement = (counterCaption) => {
        return {
            type: DECREMENT,
            counterCaption,
        }
    }
    // reducer
    export function reducerCaption(state = initValues, action) {
        const { counterCaption } = action;
        switch (action.type) {
            case INCREMENT: 
                return { ...state, [counterCaption]: state[counterCaption] + 1};
            case DECREMENT: 
                return { ...state, [counterCaption]: state[counterCaption] - 1};
            default:
                return state;
            }
    }
    
    • 6.在展示的组件里通过store.getState()获取公共的state状态,在组件加载完成后设置监听器,订阅onChange函数(当store变化,自动执行onChange函数,改变state状态,重新渲染页面)
    // Counter.js
    import React, { Component } from 'react';
    import { PropTypes } from 'prop-types';
    import store from '../store';
    import { increment, decrement } from '../modals/reducerCaption';
    import Button from '../components/Button';
    
    class Counter extends Component {
        constructor(props) {
            super(props);
    
            this.state = this.getOwnState();
        }
        componentDidMount() {
            store.subscribe(this.onChange); // 设置监听器
        }
        componentWillUnmount() {
            store.unsubscribe(this.onChange); // 关闭监听器,防止内存泄漏
        }
        getOwnState = () => {
            const { reducerCaption } = store.getState(); // 获取store的状态
            return {
                value: reducerCaption[this.props.caption]
            }
        }
        onChange = () => {
            this.setState(this.getOwnState())
        }
        // 发起一个+1的action
        onIncrement = () => {
            store.dispatch(increment(this.props.caption));
        }
        // 发起一个-1的action
        onDecrement = () => {
            store.dispatch(decrement(this.props.caption));
        }
        render() {
            const value = this.state.value;
            const { caption } = this.props;
    
            return (
                <div>
                    <Button onClick={this.onIncrement}>+</Button>
                    <Button onClick={this.onDecrement}>-</Button>
                    <span>{caption} count: {value}</span>
                </div>
            )
        }
    }
    // 对传入的值进行类型检查: 值必须为string且不能为空
    Counter.propTypes = {
        caption: PropTypes.string.isRequired,
    }
    export default Counter;
    
    • 7.当然我们不能将所有的reducer都放在一起,通过switch方法判断会使得代码太臃肿了,且不易维护,所以将不同的reducer写在不同的地方,通过combineReducers函数将这些reducer联合起来,再通过createStore方法创建一个仓库,这样我们可以通过es6解构store.getState()获取对应的reducer返回的数据。
    // store.js
    import { createStore, combineReducers } from 'redux';
    import { reducerCaption } from './modals/reducerCaption';
    import { reducerFontSize } from './modals/renderFontSize';
    
    const reducer = combineReducers({
        reducerCaption,
        reducerFontSize
    });
    
    const store = createStore(reducer);
    
    export default store;
    
    

    使用Redux-saga

    // FontSize.js
    render() {
        const {size} = this.state;
        return (
            <div>
                ...
                <Button onClick={() => {store.dispatch({type: BIGGER_ASYNC, size})}}>3秒后增加</Button>
                <Button onClick={() => {store.dispatch({type: SMALLER_ASYNC, size})}}>3秒后减小</Button>
                ...
            </div>
        )
    }
    // reducerFontSize.js
    import { put, call, takeLatest } from 'redux-saga/effects';
    const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
    function* biggerAsync(action) {
        const { size } = action;
        yield call(delay, 3000);
        yield put({ type: BIGGER, size});
    }
    function* smallerAsync(action) {
        const { size } = action;
        yield call(delay, 3000);
        yield put({ type: SMALLER, size});
    }
    export function* asyncSaga() {
        yield takeLatest(BIGGER_ASYNC, biggerAsync);  // 只监听最新的请求,可以防止多次请求,在短时间频繁点击时,只执行一次。
        yield takeLatest(SMALLER_ASYNC, smallerAsync);
    }
    // modals目录下新建rootSaga.js
    import { all } from 'redux-saga/effects';
    import { asyncSaga } from './reducerFontSize';
    
    export default function* rootSaga() {
        yield all([
            asyncSaga(),
        ])
    }
    // store.js
    import { createStore, combineReducers, applyMiddleware } from 'redux';
    import { reducerCaption } from './modals/reducerCaption';
    import { reducerFontSize } from './modals/reducerFontSize';
    import createSagaMiddleware from 'redux-saga';
    import rootSaga from './modals/rootSaga';
    
    const sagaMiddleware = createSagaMiddleware()
    let middlewares = []
    middlewares.push(sagaMiddleware)
    
    const reducer = combineReducers({
        reducerCaption,
        reducerFontSize
    });
    const store = createStore(reducer, applyMiddleware(...middlewares));
    
    sagaMiddleware.run(rootSaga);
    
    export default store;
    
    • 3.rootSaga.js将不同组件的异步操作集中在一起,然后通过sagaMiddleware.run()一起执行

    相关文章

      网友评论

          本文标题:Redux实现状态管理的小demo

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