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

Prev: Redux学习笔记-Vol.1-介绍

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({},{
        todos: [
            ...state.todos,//ES6大法好
            {
                text: action.text,complete: false
            }
        ]
    });
    
case TOGGLE_TODO:
    return Object.assign({},{
        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({},{
                        completed: !todo.completed
                    });
                }
                return todo;
            });
    }
}

function todoApp(state = initialState,action){
    switch(action.type){
        case SET_VISIBILITY_FILTER:
            return Object.assign({},{
                visibilityFilter: action.filter
            });
        case ADD_TODO:
        case TOGGLE_TODO:
            return Object.assign({},{
                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 = [],{
                        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保存起来,这一次的数据流结束。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如果组件之中有复用的代码,需要重新创建一个父类,父类中存储公共代码,返回子类,同时把公用属性...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例如我们的 setState 函数式同步执行的,我们的事件处理直接绑定在了 dom 元素上,这些都跟 re...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom 转为真实 dom 进行挂载。其实函数是组件和类组件也是在这个基础上包裹了一层,一个是调...
react 本身提供了克隆组件的方法,但是平时开发中可能很少使用,可能是不了解。我公司的项目就没有使用,但是在很多三方库中都有使用。本小节我们来学习下如果使用该...
mobx 是一个简单可扩展的状态管理库,中文官网链接。小编在接触 react 就一直使用 mobx 库,上手简单不复杂。
我们在平常的开发中不可避免的会有很多列表渲染逻辑,在 pc 端可以使用分页进行渲染数限制,在移动端可以使用下拉加载更多。但是对于大量的列表渲染,特别像有实时数据...
本小节开始前,我们先答复下一个同学的问题。上一小节发布后,有小伙伴后台来信问到:‘小编你只讲了类组件中怎么使用 ref,那在函数式组件中怎么使用呢?’。确实我们...
上一小节我们了解了固定高度的滚动列表实现,因为是固定高度所以容器总高度和每个元素的 size、offset 很容易得到,这种场景也适合我们常见的大部分场景,例如...
上一小节我们处理了 setState 的批量更新机制,但是我们有两个遗漏点,一个是源码中的 setState 可以传入函数,同时 setState 可以传入第二...
我们知道 react 进行页面渲染或者刷新的时候,会从根节点到子节点全部执行一遍,即使子组件中没有状态的改变,也会执行。这就造成了性能不必要的浪费。之前我们了解...
在平时工作中的某些场景下,你可能想在整个组件树中传递数据,但却不想手动地通过 props 属性在每一层传递属性,contextAPI 应用而生。
楼主最近入职新单位了,恰好新单位使用的技术栈是 react,因为之前一直进行的是 vue2/vue3 和小程序开发,对于这些技术栈实现机制也有一些了解,最少面试...
我们上一节了了解了函数式组件和类组件的处理方式,本质就是处理基于 babel 处理后的 type 类型,最后还是要处理虚拟 dom。本小节我们学习下组件的更新机...
前面几节我们学习了解了 react 的渲染机制和生命周期,本节我们正式进入基本面试必考的核心地带 -- diff 算法,了解如何优化和复用 dom 操作的,还有...
我们在之前已经学习过 react 生命周期,但是在 16 版本中 will 类的生命周期进行了废除,虽然依然可以用,但是需要加上 UNSAFE 开头,表示是不安...
上一小节我们学习了 react 中类组件的优化方式,对于 hooks 为主流的函数式编程,react 也提供了优化方式 memo 方法,本小节我们来了解下它的用...
开源不易,感谢你的支持,❤ star me if you like concent ^_^
hel-micro,模块联邦sdk化,免构建、热更新、工具链无关的微模块方案 ,欢迎关注与了解
本文主题围绕concent的setup和react的五把钩子来展开,既然提到了setup就离不开composition api这个关键词,准确的说setup是由...
ReactsetState的执行是异步还是同步官方文档是这么说的setState()doesnotalwaysimmediatelyupdatethecomponent.Itmaybatchordefertheupdateuntillater.Thismakesreadingthis.staterightaftercallingsetState()apotentialpitfall.Instead,usecom