Redux实现状态管理的小demo

2019-04-08  本文已影响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示例功能点

代码地址:

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

功能实现

npm install -g create-react-app
create-react-app --version
// 我的版本是2.1.1
create-react-app demo
// 新建文件
|-- |-- 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';
// 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;
        }
}
// 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;
// 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;
上一篇 下一篇

猜你喜欢

热点阅读