avatar

目录
React状态管理之redux

redux特点

  1. Redux 是 JavaScript 状态容器,提供可预测化的状态管理。
  2. 应用中所有的 state 都以一个对象树的形式储存在一个单一的 store 中。 惟一改变 state 的办法是触发 action,一个描述发生什么的对象。 为了描述 action 如何改变 state 树,你需要编写 reducers。
  3. 但是模版代码太多,每次改一点业务动辄就需要改四五个文件,着实令人心累。


示例代码

  1. pageA/store/actions.js
    javascript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    import axios from 'axios'

    /**
    * action type
    * INCREMENT 增加
    * DECREMENT 减少
    * CHANGE 增加相关的值
    * GET_OPTIONS 从服务端获取数据
    */
    export const INCREMENT = 'INCREMENT'
    export const DECREMENT = 'DECREMENT'
    export const CHANGE = 'CHANGE'
    export const GET_OPTIONS = 'GET_OPTIONS'

    /**
    * action creator
    * increase 增加
    * decrease 减少
    * change 增加相关的值
    * getOptions 从接口获取选项值
    */
    export const increase = () => {
    return { type: INCREMENT }
    }
    export const decrease = () => {
    return { type: DECREMENT }
    }
    export const change = value => {
    return {
    type: CHANGE,
    payload: value
    }
    }
    export const getOptions = () => dispatch => {
    axios.get('/api/pageA/options')
    .then(res => {
    dispatch({
    type: GET_OPTIONS,
    payload: res.data.data
    })
    })
    }
  2. pageA/store/reducer.js
    javascript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    import * as actions from './actions'

    /**
    * count 计数
    * optionList 选项值列表
    */
    const initState = {
    count: 0,
    optionList: [],
    }

    export default function counter(state = initState, action) {
    switch (action.type) {
    case actions.INCREMENT:
    return { ...state, count: state.count + 1 };
    case actions.DECREMENT:
    return { ...state, count: state.count - 1 };
    case actions.CHANGE:
    return { ...state, count: state.count + Number(action.payload) };
    case actions.GET_OPTIONS:
    return { ...state, optionList: action.payload };
    default:
    return state;
    }
    }
  3. pageA/container/main.js
    javascript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    import { connect } from 'react-redux'
    import { increase, decrease, change, getOptions } from '../store/actions'
    import view from '../component/main'

    const mapStateToProps = store => {
    const pageAStore = store.pageA

    return {
    count: pageAStore.count,
    optionList: pageAStore.optionList,
    }
    }

    // const mapDispatchToProps = (dispatch, ownProps) => {
    // return {
    // increase: () => dispatch(increase()),
    // decrease: () => dispatch(decrease()),
    // change: value => dispatch(change(value)),
    // getOptions: () => dispatch(getOptions()),
    // }
    // }

    // 相当于上一种写法的简写
    const mapDispatchToProps = {
    increase,
    decrease,
    change,
    getOptions
    }

    export default connect(mapStateToProps, mapDispatchToProps)(view)
  4. pageA/component/main.jsx
    javascript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    import React, { useState, useEffect } from 'react';

    import './main.css';

    function PageA({
    count, optionList, increase,
    decrease, change, getOptions,
    }) {
    /**
    * 输入框的值
    */
    const [inputValue, setInputValue] = useState('')

    // 输入框值变化
    const handleInputChange = event => {
    setInputValue(event.target.value)
    }

    useEffect(() => {
    getOptions()
    }, [getOptions])

    return (
    <div className="page-a">
    page a

    <br />
    <br />

    <h2>count: {count}</h2>
    <button onClick={increase}>increase</button>
    <button onClick={decrease}>decrease</button>

    <br />
    <br />

    <input value={inputValue} onChange={handleInputChange} type="text" />
    <button onClick={() => change(inputValue)}>change</button>

    <br />
    <br />

    <select name="select" id="select">
    {
    optionList.map(item => (
    <option key={item} value={item}>{item}</option>
    ))
    }
    </select>
    </div>
    );
    }

    export default PageA;


注意点

  1. redux可以用 redux-thunk 处理请求接口这样的副作用
  2. redux可以用 combineReducers 整合reducer子模块
    javascript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // src/store.js
    import { combineReducers, createStore, applyMiddleware } from 'redux';
    import thunk from 'redux-thunk';

    import pageA from './pageA/store/reducer'

    const rootReducer = combineReducers({
    pageA,
    })

    const store = createStore(rootReducer, applyMiddleware(thunk));

    export default store

拓展:create-react-app 添加 proxy 接口代理

  1. npm安装 http-proxy-middleware 模块
  2. scr目录下添加 setupProxy.js 文件
    javascript
    1
    2
    3
    4
    5
    6
    7
    const proxy = require('http-proxy-middleware');

    module.exports = function (app) {
    app.use(proxy.createProxyMiddleware('/api', {
    target: 'http://127.0.0.1:8000/',
    }));
    };
文章作者: 盛顺炎
文章链接: https://www.shengshunyan.xyz/2020/04/11/React%E7%8A%B6%E6%80%81%E7%AE%A1%E7%90%86%E4%B9%8Bredux/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 果实的技术分享
打赏
  • 微信
    微信
  • 支付寶
    支付寶

评论