随着js应用的日益复杂化,状态管理越来越成为前端开发的必要条件。一些库依然没有提供处理state中数据问题的合适方法,恰好redux可以帮我们搞定这个难题。
核心概念
要更新state中的数据,就要发起一个action来描述发生了什么。然后用一个reducer函数,接收 state 和 action并返回新state,来实现state的更新。当然,实际开发中往往需要编写很多小函数分别管理state的一部分,再开发一个reducer调用这两个reducer,管理整个state。
state可能是这样的:
{
todos: [{
text: 'Eat food',
completed: true
}, {
text: 'Exercise',
completed: false
}],
visibilityFilter: 'SHOW_COMPLETED'
}
action可能是这样的:
{ type: 'ADD', text: 'Go to swimming pool' }
{ type: 'TOGGLE', index: 1 }
{ type: 'SET_FILTER', filter: 'SHOW_ALL' }
reducer可能是这样:
function Filter(state = 'SHOW_ALL', action) {
if (action.type === 'SET_FILTER') {
return action.filter
} else {
return state
}
}
function todos(state = [], action) {
switch (action.type) {
case 'ADD':
return state.concat([{ text: action.text, completed: false }])
case 'TOGGLE':
return state.map((todo, index) =>
action.index === index
? { text: todo.text, completed: !todo.completed }
: todo
)
default:
return state
}
}
function todoApp(state = {}, action) {
return {
todos: todos(state.todos, action),
visibilityFilter: visibilityFilter(state.visibilityFilter, action)
}
}
三大原则:
1、数据源是单一的:
整个应用的state被储存在一棵object tree中,并且这个object tree只存在于唯一一个store中。
2、state是只读的:
唯一改变 state 的方法就是触发action。
3、使用纯函数执行修改:
为了描述 action 如何改变 state tree,你需要编写reducers。
Action:
把数据传到store,是store数据的唯一来源。一般用store.dispatch()将action传到store。
const ADD_TODO = 'ADD_TODO'
{
type: ADD_TODO, // type字段表示将要执行的动作
text: 'Build my first Redux app'
}
如果项目规模较大,可以单独存放action:
import { ADD_TODO, REMOVE_TODO } from '../actionTypes'
例子:
/* 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 创建函数 */
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:
1、接受旧的state和action,返回新state。
2、一定要保持纯净,单纯执行计算,不要修改入参,不要执行跳转或api请求,不要3、调用非纯函数(Date.now()或Math.random()等。)
3、首次执行时state为undefined,此时可以设置返回初始state。
function todos(state = [], action) {
switch (action.type) {
case ADD_TODO:
return [
...state,
{
text: action.text,
completed: false
}
]
case TOGGLE_TODO:
return state.map((todo, index) => {
if (index === action.index) {
return Object.assign({}, todo, {
completed: !todo.completed
})
}
return todo
})
default:
return state
}
}
function todoApp(state = initialState, action) {
switch (action.type) {
case SET_VISIBILITY_FILTER:
return Object.assign({}, state, {
visibilityFilter: action.filter
})
case ADD_TODO:
return Object.assign({}, state, {
todos: todos(state.todos, action)
})
case TOGGLE_TODO:
return Object.assign({}, state, {
todos: todos(state.todos, action)
})
default:
return state
}
}
源码:
import { combineReducers } from 'redux'
import {
ADD,
TOGGLE,
SET_FILTER,
Filters
} from './actions'
const { SHOW_ALL } = Filters
function Filter(state=SHOW_ALL,action){
switch(action.type){
case SET_FITER:
return action.filter
default:
return state
}
}
function todos(state=[], action){
switch(action.type){
case ADD:
return [
...state,
{
text: action.text,
completed: false
}
]
case TOGGLE:
return state.map((todo, index) =>{
if(index===action.index){
return Object.assign((),todo, {
completed: !todo.completed
})
}
return todo
})
default:
return state
}
}
const todoApp = combineReducers({
Filter,
todos
})
export default todoApp
Store:
只有一个单一的store,把action和reducer联系到一起。
职责:维持state,提供getState()获取state,提供dispatch(action)更新state,
通过subscribe(listener)注册监听器,通过subscribe(listener)返回的函数注销监听器。
我们把上面的combineReducer导入进来,并传递createStore:
import { createStore } from 'redux'
import todoApp from './reducers'
let store = createStore(todoApp)
先看下redux暴露出来的几个方法:### 1、bindActionCreators()、
2、combineReducers()、
3、createStore(reducers函数, 初始值initialStore, 中间件middleware)
返回的方法主要有:
网友评论