Redux基本使用

版权声明:转载需注明出处 https://blog.csdn.net/samfung09/article/details/83243056

话不多说,先上图

依上图所示,简单分析redux工作流程。

Store根据Reducer返回的state创建公共state仓库,组件中引入Store即可用store.getState()获取公共state;

如果组件中想要改变公共state可以用store.dispatch(action)派发出一个动作通知Store,接到通知后的Store将这个动作以及原来的公共state传给Reducer,然后Reducer经过处理返回新的公共state给Store,Store再将Reducer新返回的state替换原来的state,这时在组件中通过store.subscribe(处理函数)监听公共state变化。

没错,听起来确实有点绕,但动手敲一遍思路就清晰多了。其实跟vuex思路差不多。

下面是基本使用

安装redux

npm install redux --save

在src目录下创建store目录,store目录下创建index.js和reducer.js两个文件。

store/index.js

import {createStore} from 'redux';
import reducer from './reducer';

// 第二个参数用来配置chrome中的redux扩展
const store = createStore(
    reducer,
    window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);

export default store;

这里需要注意的是createStore函数的第二个参数是为了chrome浏览器的redux扩展,先要翻墙安装redux devtools。

store/reducer.js

// 深度克隆对象函数
function deepCopy(obj){
    //如果是非对象直接返回,包括function(特殊)
    if(typeof obj !== 'object') return obj;
    //如果是null
    if(obj === null) return null;
    //如果是日期对象
    if(obj instanceof Date) return new Date(obj);
    //如果是正则对象
    if(obj instanceof RegExp) return new RegExp(obj);
    //不直接定义[]或{}是为了要保留该对象的原型链
    var tempObj = new obj.constructor();
    for(var key in obj){
        tempObj[key] = typeof obj[key] == 'object' ? deepCopy(obj[key]) : obj[key];
    }  
    return tempObj;
}

const defaultState = {
    list: [1,2,3]
}

export default (state = defaultState, action) => {
    if(action.type === 'add_list_item'){
        let newState = deepCopy(state);     //reducer不能直接改变state,需要复制出来一份
        newState.list.push(action.value);
        return newState;
    }
    return state;
}

这里需要注意的是Reducer中不要直接更改state,可以先复制出一份副本,修改副本,然后将副本返回给Store。

组件代码

import React, {Component} from 'react';
import 'antd/dist/antd.css';
import {Input, Button, List} from 'antd';
import store from './store';

class TodoList extends Component{
    constructor(props){
        super(props);
        this.state = {
            inputValue: '',
            list: store.getState().list  //公共state中的list
        }
        // 监听store变化
        store.subscribe(this.handleStoreChange);
    }

    render(){
        console.log(this.state)
        return (
            <div>
                <Input 
                    placeholder="请输入" 
                    style={{width:'300px',marginRight:'10px'}} 
                    value={this.state.inputValue}
                    onChange={this.handleInputChange}
                />
                <Button type="primary" onClick={this.addListItem}>提交</Button>
                <List
                    style={{width:'300px', marginTop:'10px'}}
                    bordered
                    dataSource={this.state.list}
                    renderItem={item => (<List.Item>{item}</List.Item>)}
                />
            </div>
        )
    }

    handleInputChange = e => {
        this.setState({inputValue: e.target.value})
    }

    addListItem = () => {
        // 派发action
        store.dispatch({
            type: 'add_list_item',
            value: this.state.inputValue
        })
    }
    
    handleStoreChange = () => {     // 当store发生改变时做的处理,store.subscribe中添加
        this.setState({list: store.getState().list});
    }
}

export default TodoList;

这里组件中引入了antd布局,而且我直接使用了箭头函数在类中定义函数,这是es7语法,还是推荐在constructor中绑定this。

效果图

redux devtools

在实际应用中,我们也应该将action统一规范管理,我们可以在store目录下再新建actionTypes.js和actionCreator.js两个文件。

actionTypes.js规范action.type

//添加列表项的action.type
export const ADD_LIST_ITEM = 'add_list_item';

actionCreator.js统一action

import {ADD_LIST_ITEM} from './actionTypes';

// 返回添加列表项的action
export let AddListItemAction = value => ({
    type: ADD_LIST_ITEM,
    value
})

然后在组件中引入使用即可。

猜你喜欢

转载自blog.csdn.net/samfung09/article/details/83243056