安装
cnpm install react-redux redux --save
文档地址: http://cn.redux.js.org/docs/introduction/index.html
作用:无论是移动端还是 pc 端,当你使用 React 或者 vue 开发组件化的 SPA 程序时,组件之间共享信息是一个非常大的问题。例如,用户登录之后客户端会存储用户信息(如userid、头像等),而系统的很多个组件都会用到这些信息,例如收藏、点赞、评论等。这些组件在用到用户信息时,难道每次使用都重新获取一遍?———— 自然不是这样。因此每个系统都需要一个管理多组件使用的公共信息的功能,这就是 Redux 的作用。
Store 就是保存数据的地方,你可以把它看成一个容器。整个应用只能有一个 Store。
Redux提供createStore
这个函数来生成store
import { createStore } from 'redux';
const store = createStore(fn);
上面代码中,creatStore
函数接收了另一个函数作为参数,返回新生成的store对象
Store有两个核心方法,分别是 getState
和 dispatch
。前者用来获取store的状态(state),后者用来修改store的状态
State 的变化,会导致 View 的变化。但是,用户接触不到 State,只能接触到 View。所以,State 的变化必须是 View 导致的。Action 就是 View 发出的通知,表示 State 应该要发生变化了。
Action 是行为的抽象
Action 是一个对象。其中的type属性是必须的,表示 Action 的名称。其他属性可以自由设置
const action = {
type: 'ADD_TODO',
payload: 'Learn Redux'
};
上面代码中,Action 的名称是ADD_TODO,它携带的信息是字符串Learn Redux。
可以这样理解,Action 描述当前发生的事情。改变 State 的唯一办法,就是使用 Action。它会运送数据到 Store。
Action Creator
View 要发送多少种消息,就会有多少种 Action。如果都手写,会很麻烦。可以定义一个函数来生成 Action,这个函数就叫 Action Creator。
const ADD_TODO = '添加 TODO';
function addTodo(text) {
return {
type: ADD_TODO,
text
}
}
const action = addTodo('Learn Redux');
上面代码中,addTodo函数就是一个 Action Creator。
store.dispatch( )
store.dispatch()是 View 发出 Action 的唯一方法。将action传入到store
import { createStore } from 'redux';
const store = createStore(fn);
store.dispatch({
type: 'ADD_TODO',
payload: 'Learn Redux'
});
上面代码中,store.dispatch( )
接受一个action对象作为参数,将他发送出去。
结合Action Creator,代码改写如下
store.dispatch(addTodo('Learn Redux'))
Store 收到 Action 以后,必须给出一个新的 State,这样 View 才会发生变化。而这正是 Reducer 要做的事情,更新 state
Reducer:是一个普通的函数,用来修改store的状态,传入两个参数state
,action
。其中state为当前的状态(可通过store.getState()获取),而action为当前触发的行为(通过store.dispath(action)调用触发)。
reducer(state,action)函数,返回store最新的state的值
eg:
const defaultState = 0;
//定义了一个reducer函数
const reducer = (state = defaultState, action) => {
switch (action.type) {
case 'ADD':
return state + action.payload;
default:
return state;
}
};
//调用函数,返回新的state
const state = reducer(1, {
type: 'ADD',
payload: 2
});
上面代码中,reducer函数收到名为ADD的 Action 以后,就返回一个新的 State,作为加法的计算结果。
但是在实际应用中,Reducer函数并不需要像上面这样子调用,store.dispatch
方法会触发Reducer的自动执行,为此Store 需要知道 Reducer 函数,做法就是在生成 Store 的时候,将 Reducer 传入createStore方法。
import { createStore } from 'redux';
const store = createStore(reducer)
上面代码中,createStore接收reducer作为参数,生成了一个新的store,所以当以后store.dispatch
发送过来一个新的Action,就会自动调用Reducer得到新的state
为什么这个函数叫做Reducer呢?因为他可以作为数组的reduce
方法的参数,JavaScript中reduce()方法不完全指南
eg:
const actions = [
{ type: 'ADD', payload: 0 },
{ type: 'ADD', payload: 1 },
{ type: 'ADD', payload: 2 }
];
const total = actions.reduce(reducer,0) //3
上面代码中,数组actions表示依次有三个 Action,分别是加0、加1和加2。数组的reduce方法接受 Reducer 函数作为参数,就可以直接得到最终的状态3。
纯函数
Reducer函数最重要的特性是,他是一个纯函数,也就是说,只要是同样的输入,必定得到同样的输出
纯函数是函数式编程的概念,必须遵守一下的约束:
由于Reducer是纯函数,就可以保证同样的state,必定得到同样的view,但也正因为这一点,Reducer函数里面不能改变state,必须返回全新的一个对象,eg:
//state是一个对象
function reducer(state,action){
return Object.assign({},state,{tingToChange})
//或者
return {...state,...newState}
}
//state是一个数组
function reducer(state,action){
return [...state,newItem]
}
最好把 State 对象设成只读。你没法改变它,要得到新的 State,唯一办法就是生成一个新对象。这样的好处是,任何时候,与某个 View 对应的 State 总是一个不变的对象。
store.subscribe( )
Store允许使用store.subscribe
方法设置监听函数,一但State发生变化,就会自动执行这个函数
import {createStore} from "redux"
const store = createStore(reducer)
store.subscribe(listener)
显然,只要把view的更新函数(对于react项目,就是组件的render方法或者setState方法)放入listener,就会实现view的自动渲染
store.subscribe
方法返回一个函数,调用这个函数就可以解除监听
let unsubscribe= store.subscribe(()=>{
console.log(store.getState())
})
unsubscribe()
combineReducers
Redux 提供了一个combineReducers方法,用于 Reducer 的拆分。你只要定义各个子 Reducer 函数,然后用这个方法,将它们合成一个大的 Reducer。
import { combineReducers } from 'redux';
const chatReducer = combineReducers({
chatLog,
statusMessage,
userName
})
export default todoApp;
上面代码中,Reducer 函数被拆成了三个小函数,每一个负责生成对应的属性。
combineReducers()做的就是产生一个整体的 Reducer 函数。该函数根据 State 的 key 去执行相应的子 Reducer,并将返回结果合并成一个大的 State 对象。
Redux 提供了一个combineReducers
方法,用于 Reducer 的拆分。你只要定义各个子 Reducer 函数,然后用这个方法,将它们合成一个大的 Reducer。
combineReducers()做的就是产生一个整体的 Reducer 函数。该函数根据 State 的 key 去执行相应的子 Reducer,并将返回结果合并成一个大的 State 对象。
这是一个reducer的小栗子:
const todo = (state,action)=>{
switch(action.type){
case "ADD_TODO":
return {
id: action.id,
text: action.text,
completed: false
}
case "TOGGLE_TODO":
if(state.id !== action.id){return state}
//取反,如果completed是ture返回false,反之亦然
//state是对象的默认值,Object.assign方法将state和后面的对象合并成一个新对象,如果两者属性名相同,则后面的会覆盖前面的值
return Object.assign({},state,{completed: !state.completed})
default: return state
}
}