三、Redux简介及其主要组成
1,简介
Redux应用需要遵循三大原则,否则程序很容易出现难以察觉的问题。
①唯一数据源
Redux只维护一个全局的状态对象,存储在Redux的store中。唯一数据源是一种集中式管理应用状态的方式,便于监控任意时刻应用的状态和调试应用,减少出错的可能性。
②保持应用状态只读
在任何时候都不能直接修改应用状态。当需要修改应用状态时,必须发送一个action,由这个action描述如何修改应用状态。
③应用状态的改变通过纯函数完成
action表明修改应用状态的意图,真正对应用状态做修改的是reducer。reducer必须是纯函数,所以reducer在接收到action时,不能直接修改原来的状态对象,而是要创建一个新的状态对象返回。
纯函数指的是:
- 对于同样的参数值,函数的返回结果总是相同的。
- 函数的执行不会产生副作用,例如修改外部对象或输出到I/O设备。
2,主要组成
①action:是Redux中信息的载体,是store唯一的信息来源。把action发送给store必须通过store的dispatch方法。action是普通的JavaScript对象,但每一个action必须有一个type属性描述action的类型,type一般为字符串常量。除了type属性外,action的结构完全由自己决定。一般通过action creator创建action,action creator是返回action的函数:
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 creators
//新增待办事项
export function addTodo(text) {
return {
type: ADD_TODO,
text
}
}
//修改待办事项的状态,index是待办事项在todos数组中的位置索引
export function toggleTodo(index) {
return {
type: TOGGLE_TODO,
index
}
}
//筛选当前显示的待办事项列表
export function setVisibilityFilter(filter) {
return {
type: SET_VISIBILITY_FILTER,
filter
}
}
②reducer:action用于描述应用发生了什么操作,reducer则根据action做出相应,决定如何修改应用的状态state。既然是修改state,那么就应该在编写reducer之前设计好state。state既可以包含服务器端获取的数据,也可以包含UI状态:
{
todos: [{
text: 'Learn React',
completed: true
},{
text: 'Learn React',
completed: false
}],
visibilityFilter: 'SHOW_COMPLETED'
}
创建reducer:
import { VisibilityFilters } from './actions'
const initialState = {
todos: [],
visibilityFilter: VisibilityFilters.SHOW_ALL
}
//reducer
function todoApp(state = initialState, action) {
switch (action.type) {
case SET_VISIBILITY_FILTER:
return { ...state, visibilityFilter: action.filter }
// 新增待办事项
case ADD_TODO:
// 使用了ES6的扩展语法
return {
...state, todos: [
...state.todos,
{
text: action.text,
completed: false
}
]
}
// 修改待办事项的状态(已完成/未完成)
case TOGGLE_TODO:
return {
...state, todos: state.todos.map((todo, index) => {
if (index === action.index) {
return {
...todo, completed: !todo.completed
}
}
return todo
})
}
default:
return state
}
}
当应用变得复杂时,这个reducer也会逐渐变复杂,这时,一般会拆分出多个reducer,每个reducer处理state中的部分状态:
todos.js:
const todos = (state = [], action) => {
switch (action.type) {
case 'ADD_TODO':
return [
...state,
{
id: action.id,
text: action.text,
completed: false
}
]
case 'TOGGLE_TODO':
return state.map(todo =>
(todo.id === action.id)
? {...todo, completed: !todo.completed}
: todo
)
default:
return state
}
}
export default todos
visibilityFilter.js:
const visibilityFilter = (state = 'SHOW_ALL', action) => {
switch (action.type) {
case 'SET_VISIBILITY_FILTER':
return action.filter
default:
return state
}
}
export default visibilityFilter
todoApp.js:
import todos from './todos'
import visibilityFilter from './visibilityFilter'
const todoApp = combineReducers({
todos,
visibilityFilter
})
export default todoApp
每个拆分的reducer只接收它负责的state中的部分属性。Redux还提供了一个combineReducers函数,用于合并多个reducer。
还可以为combineReducers接受的参数对象指定和reducer的函数名不同的key值:
可见,combineReducers传递给每个reducer的state中的属性取决于它的参数对象和key值。
③store
store是Redux中的一个对象,也是action和reducer之间的桥梁。store主要负责以下几个工作:
- 保存应用状态
- 通过方法getState()访问应用状态
- 通过方法dispatch(action)发送更新状态的意图
- 通过方法subscribe(listener)注册监听函数、监听应用状态的改变
一个Redux应用中只有一个store,store保存了唯一数据源。store通过createStore()函数创建,创建时需要传递reducer作为参数,创建todos应用的store代码如下:
import { createStore } from 'redux'
import todoApp from './reducers'
const store = createStore(todoApp)
创建store时还可以设置应用的初始状态:
const store = createStore(todoApp,initialState)
store创建完成后,就可以通过getState()获取当前应用的状态state:
const store = store.getState()
当需要修改state时,通过store的dispatch()方法发送action。例如,发送一个新增待办事项的action:
function addTodo(text) {
return {type: 'ADD_TOTO',text}
}
store.dispatch(addTodo('Learn about actions'))
当todoApp这个reducer处理完成addTodo这个action时,应用的状态会被更新,此时通过store.getState()可以得到最新的应用状态。为了能准确知道应用状态更新的时间,需要向store注册一个监听函数:
let unsubscribe = store.subscribe(() => {
console.log(store.getState())
})
这样每当应用状态更新时,最新的应用状态就会被打印出来。当需要取消监听时,直接调用store.subscribe返回的函数即可:
unsubscribe();
总结:
- 调用store.dispatch(action)。一个action是一个用于描述“发生了什么”的对象。store.dispatch(action)可以在应用的任何地方调用,包括组件、XHR回调,甚至在定时器中。
- Redux的store调用reducer函数。store传递两个参数给reducer:当前应用的状态和action。reducer必须是一个纯函数,它的唯一职责是计算下一个应用的状态。
- 根reducer会把多个子reducer的返回结果组合成最终的状态。跟reducer的构建形式完全取决于用户。Redux提供了combineReducers,方便把多个拆分的子reducer组合到一起。
- Redux的store保存根reducer返回的完整应用状态。此时,应用状态才完成更新。如果UI需要根据应用状态进行更新,那么这就是更新UI的时机。对于React而言,可以在此时调用组件的setState方法,根据新的应用状态更新UI。