Redux学习笔记-Vol.2-基础

作者: kyrieliu | 来源:发表于2016-12-30 15:37 被阅读23次

    基础

    Action

    Action是把数据从应用传到store的有效载荷。它是store数据的唯一来源,一般通过store.dispatch()将action传到store。
    举个栗子:

    const ADD_TODO = 'ADD_TODO';
    
    //一个action可以表达为:
    {
        type: ADD_TODO,
        text: 'Build my first Redux app'
    }
    

    说白了,action就是一个普通的javascript对象,但是有一点要注意:约定这个表示action的对象必须有一个type字段,来表示将要执行的动作。
    尽量减少在action中传递数据

    Action Creator

    Action Creator就是生成action的方法。

    function addTodo(text){
        return {
            type: 'ADD_TODO',
            text
        }
    }
    

    在Redux中,只需把action creator的结果返回给dispatch()即可发起一次dispatch过程。

    dispatch(addTodo(text));
    

    或者,创建一个被绑定的action creator来自动dispatch:

    const boundAddTodo = (text) => dispatch(addTodo(text));
    boundAddTodo();
    

    目前为止,我们写好了一个action.js

    //action type
    export const ADD_TODO = 'ADD_TODO';
    export const TOGGLE_TODO = 'TOGGLE_TODO';
    export const SET_VISIBILITY_FILTER = 'SET_VISIBILITY_FILTER';
    
    
    //其它常量
    export const VisibilityFilters = {
        SHOW_ALL: 'SHOW_ALL',
        SHOW_COMPLETED: 'SHOW_COMPLETED',
        SHOW_ACTIVE: 'SHOW_ACTIVE'
    };
    
    
    //action creator
    export function addTodo(text){
        return {
            type: ADD_TODO,
            text
        }
    }
    
    export function toggleTodo(index){
        return {
            type: TOGGLE_TODO,
            index
        }
    }
    
    export function setVisibilityFilter(filter){
        return {
            type: SET_VISIBILITY_FILTER,
            filter
        }
    }
    

    Reducer

    有了action以后,现在需要reducer来指明如何更新state。

    State结构

    要明确的一点是,在Redux应用中,所有的state都被保存在一个单一的对象中。
    举个栗子,一个todo应用,需要保存两种不同的数据

    • 当前选中的任务过滤条件
    • 完整的任务列表
    {
        visiibilityFilter: 'SHOW_ALL',
        todos: [
            {
                text: 'Consider using Redux',
                complete: true
            },
            {
                text: 'Keep all state in a single tree',
                complete: false
            }
        ]
    }
    

    处理action

    Reducer是一个纯函数,接受旧的state和action,返回新的state,形如:

        (previousState, action) => newState
    

    保持reducer纯净非常重要,永远不要在reducer中做这些操作:

    • 修改传入的参数
    • 执行有副作用的操作,如API请求和路由跳转
    • 调用非纯函数,如Date.now()Math.random()

    一个纯净的reducer是什么样的呢?
    只要传入的参数相同,返回计算得到的下一个state就一定相同。
    好,开始写reducer。

    import { VisibilityFilters } from './actions';
    
    const initialState = {
        visibilityFilter: VisibilityFilter.SHOW_ALL,
        todo: []
    };
    
    function todoApp(state = initialState, action){
        switch (action.type){
            case SET_VISIBILITY_FILTER:
                return  Object.assign({}, state, {
                    visibilityFilter: action.filter
                });
            default:
                return state;
        }
    }
    

    注意:

    1. 不要修改state。上面的代码中只是使用Object.assign()创建了一个副本。
    2. default的情况下,返回旧的state在未知的情况下,一定要返回旧的state!

    处理多个action

    先增加两个ADD_TODOTOGGLE_TODO

    case ADD_TODO:
        return Object.assign({}, state, {
            todos: [
                ...state.todos,//ES6大法好
                {
                    text: action.text,
                    complete: false
                }
            ]
        });
        
    case TOGGLE_TODO:
        return Object.assign({}, state, {
            todos: state.todos.map(function(todo, index){
                if (index === action.index){
                    return Object.assign({}, todo, {
                        completed: !todo.completed;
                    });
                }
                return todo;
            });
        });
    

    拆分reducer

    function todos(state = [], action){
        switch(action.type){
            case ADD_TODO:
                return [
                    ...state,
                    {
                        text: action.text,
                        completed: false
                    }
                ];
            case TOGGLE_TODO:
                return state.map(function(todo, index){
                    if (index === action.index){
                        return Object.assign({}, todo, {
                            completed: !todo.completed
                        });
                    }
                    return todo;
                });
        }
    }
    
    function todoApp(state = initialState, action){
        switch(action.type){
            case SET_VISIBILITY_FILTER:
                return Object.assign({}, state, {
                    visibilityFilter: action.filter
                });
            case ADD_TODO:
            case TOGGLE_TODO:
                return Object.assign({}, state, {
                    todos: todos(state.todos, action)
                });
            default:
                return state;
        }
    }
    

    todos依旧接受state,但是这里的state变成了一个数组,todoApp只把需要更新的那一部分state传给todos。这就是reducer合成,是开发Redux应用最基础的模式。
    用同样的方法把visibilityFilter拆分出来:

    function visibilityFilter(state = SHOW_ALL, action){
        switch(action.type){
            case SET_VISIBILITY_FILTER:
                return action.filter;
            default:
                return state;
        }
    }
    

    然和修改总的reducer

    function todoApp(state = {}, action){
        return {
            visibilityFilter: visibilityFilter(state.visibilityFilter, action),
            todos: todos(state.todos, action)
        };
    }
    

    合并的事,就交给Redux帮你来做:

    import { combineReducers } from 'redux';
    
    const todoApp = combineReducers({
        visibilityFilter,
        todos
    });
    
    export default todoApp;
    

    ES6大法好
    combineReducers接受的是一个对象,返回一个函数。由此,我们可以把所有的顶级的reducer放到一个独立文件中,通> > 过export暴露出每个reducer函数,然后用import * as reducer引入一个以他们名字作为key的Object:

    import { combineReducers } from 'redux';
    import * as reducer from './reducers';
    
    const todoApp = combineReducers(reducer);
    //ES6大法好!
    

    截至目前,我们得到了一个完整的reducers.js

    import { combineReducers } from 'redux';
    import { ADD_TODO, TOGGLE_TODO, SET_VISIBILITY_FILTER, VisibilityFilters } from './actions';
    
    function visibilityFilters(state = SHOW_ALL, action){
        switch(action.type){
            case SET_VISIBILITY_FILTER:
                return action.filter;
            default:
                return state;
        }
    }
    
    function todos(state = [], action){
        switch(action.type){
            case ADD_TODO:
                return [
                    ...state,
                    {
                        text: action.text,
                        completed: false
                    }
                ];
            case TOGGLE_TODO:
                return state.map(function(todo, index){
                    if (index === action.index){
                        return Object.assign({}, todo, {
                            completed: !todo.completed
                        });
                    }
                    return todo;
                });
            default:
                return state;
        }
    }
    
    const todoApp = combineReducer({
        visibilityFilters,
        todos
    });
    
    export default todoApp;
    

    Store

    在学Store之前,我们先来回顾一下actionreducer

    • Action:用来表示“发生了什么”
    • Reducer:根据“发生了什么”来决定如何更新state

    现在需要知道的是,Store的作用就是上述两者联系起来。
    关于Store的职责:

    • 维持应用的state
    • getState()方法用来获取state
    • dispatch(action)用来分发action,进而更新state
    • subscribe(listener)注册reducer,并返回一个取消注册的函数

    FYI:Redux只有一个单一的Store!当逻辑复杂需要拆分的时候,请对Reducer下手,科科。
    Now,我们来根据已经写好了的reducer来创建store,so easy~

    import { createStore } from 'redux';
    import todoApp from './reducers';
    
    let store = createStore(todoApp);
    

    createStore()方法可以的第二个参数是可选的,用于设置state的初始状态。

    let store = createStore(todoApp, initialState);
    

    发起actions

    现在我们已经有了一个store,来看一下怎么用。

    import { addTodo, toggleTodo } from './actions';
    
    //获得state
    store.getState();
    
    //注册(订阅),state没触发一次更新,打印之
    let unsubscribe = store.subscribe(function(){
        console.log(store.getState());
    });
    
    //发起action
    store.dispatch(addTodo('finish your resume.'));
    store.dispatch(toggleTodo(0));
    
    //停止监听state更新
    unsubscribe();  
    

    看看这一part做了什么 ↓

    //创建了一个store(约定store只有一个!)
    import { createStore } from 'redux';
    import todoApp from './reducers';
    
    let store = createStore(todoApp);
    

    严格的单向数据流(Redux核心)

    1. 发起:store.dispatch(action)
    2. 传递:store将发起的action和当前的state传递给根reducer,根reducer再将这两个参数传递给子reducer们;
    3. 更新:通过了子reducer们的各司其职以后,根reducer把他们的输出合并为一个单一的state树;
    4. 保存:store将这个reducer返回的state保存起来,这一次的数据流结束。

    相关文章

      网友评论

        本文标题:Redux学习笔记-Vol.2-基础

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