来源:
Redux入门教程-阮一峰
文档:
Redux中文文档
基本概念
Store
Store是Redux保存数据的地方,一个应用只能有一个Store;
生成:
import {createStore} from 'redux'
const store=createStore(fn);
使用createStore()
来接收另一个函数作为参数生成Store对象,这个参数是Reducer;它也可以接收另一个参数,这个参数将会表示State的最初状态;
let store = createStore(todoApp, window.STATE_FROM_SERVER)
在上面的例子中,window.STATE_FROM_SERVER将会是状态初始值,如果提供了这个参数,Reducer的默认初始值将会被覆盖。
State
State是Store的一份快照,它是在一个时刻的时候的Store.
当前时刻的State使用store.getState()
获得
import {createStore} from 'redux'
const store=createStore(fn);
const state=store.getState();
State与视图层View绑定,两者相关。
Action
State的变化由View导致,Action是View发出的通知,表示使State发生变化。
Action是一个对象,其中只有type属性是必须设置的。
const action={
type:"ADD",
payload:"Learn Redux",
}
上述Action的名称为type属性,携带的信息为payload的值。
Action Create
Action Creator用来生成Action
const todoSomething="ADD";
function addTodo(payload){
return {
type:todoSomething,
payload
}
}
const action=addTodo("Learn Redux")
事实上,这里的action和上一个例子的action相同的。
addTodo函数为一个Action Creator
store.dispatch()
store.dispatch()是View发出Action的唯一方法;
import {createStore} from 'redux'
const store=createStore(fn);
store.dispatch({
type:"ADD",
payload:"Learn Redux"
})
在上面的例子里,store.dispatch()接收了一个Action作为参数。
使用store.Create后,可以将代码改写为:
store.dispatch(addTodo('Learn Redux'));
Reducer
Store接收到Action之后,将会使用Reducer来使State发生变化,进而影响到View。
Reducer是一个函数,它接收Action和State作为参数,返回一个新的State
const reducer=function (state,action){
//...
return newState;
}
我们可能会需要一个State的初始状态,这个时候,我们可以使用:
const defaultState=0;
const reducer=(state=defaultState,action)=>{
switch(action.type){
case "ADD":
return state+action.payload;
default:
return state;
}
};
const state=reducer(1,{
type:"ADD",
payload:2
})
在上面的代码中,reducer在接收到名称为ADD的Action后,将State的值进行处理并返回相加的值。
在实际运行时,Reducer不需要手动调用,store.dispatch()将会自动触发Reducer执行。
为了使得Reducer自动执行,Store需要知道Reducer,所以在Store生成时,将Reducer作为参数传入createStore();
Reducer必须是一个纯函数,所以请使用以下写法:
//State是一个对象时
function reducer(state,action){
return Object.assign({},state,{thingToChange});
//or
return {...state,...newState};
}
//State是一个数组时
function reducer(state,action){
return[...state,newItem];
}
Object.assign()将会将对象进行合并,关于该函数的详细知识,请看这里。
值得注意的是,在任何时候State都不应该发生改变,即一个时刻对应一个新的State,对应一个新的View,不应该试图对State进行改变。
reducer的拆分
在state变得巨大的时候,Reducer也会随之变大,可以使用combineReducers方法将不同的Reducer子函数进行合并为一个大函数。
import { combineReducers } from 'redux';
const chatReducer = combineReducers({
chatLog,
statusMessage,
userName
})
export default todoApp;
这种写法有一个前提:State的属性名字需要与Reducer的子函数同名,否则采用以下写法:
const reducer = combineReducers({
a: doSomethingWithA,
b: processB,
c: c
})
// 等同于
function reducer(state = {}, action) {
return {
a: doSomethingWithA(state.a, action),
b: processB(state.b, action),
c: c(state.c, action)
}
}
store.subscribe()
import { createStore } from 'redux';
const store = createStore(reducer);
store.subscribe(listener);
Store使用该方法设置监听函数,在State发生变化的时候将会自动执行。
在通常情况下,要将View的更新函数作为在listenr中,对于react,这将会是对state的更新做出反应的函数,如setState()或者是render()
store.subscribe()将会返回一个函数,调用这个函数就可以解除监听。
一个实例
这个实例中,希望实现一个面包屑,这个面包屑的显示将会随着路由的变化发生变化。
//store.js
import {createStore} from 'redux'
import reducer from '../reducer'
const default={
menuName:"首页"
}
//创建store,初始值为default
const configStore=createStore(reducer,default);
//reducer.js
import {type} from '../action'
//创建Reducer:Data,如果Action的type是"SWITCH_MENU",将会对menuName进行修改
const Data=(state,action)=>{
switch(action.type){
case "SWITCH_MENU":
return {
...state,
menuName:action.menuName
};
default:
return {...state};
}
};
export default Data;
//action
export function switchMenu(menuName){
return{
type:"SWITCH_MENU",
menuName
}
}
以上,redux的基本功能已经完成,store存储数据,reducer将会对action进行响应。