Redux实现状态管理的小demo

此项目是用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 (
            
{caption} count: {value}
) } } // 对传入的值进行类型检查: 值必须为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

  • 1.代码地址 https://github.com/Zhonghua926/demo-redux redux-saga分支
  • 2.Redux只支持同步操作,这里我使用Redux-saga中间件,来加强store,使得Redux可以调用异步操作
// FontSize.js
render() {
    const {size} = this.state;
    return (
        
... ...
) } // 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)