Redux Basic Concepts
Actions
action
是将数据从应用传递到store
的介质,是store
的唯一信息来源,使用store.dispatch()
将信息发送到store
中。
actions是纯JavaScript对象。actions必须有一个type
属性来标明正在执行的action的类型,type
属性通常被定义为字符串常量。
Action Creators
定义action的函数,函数一般返回一个action
。如果想要发起一个dispatch
,需要将action createor的结果传入dispatch
作为参数。例如一个todo应用中:
// action creator
function addTodo(text) {
return {
type: ADD_TODO,
text
}
}
// dispatch
dispatch(addTodo(text))
或者绑定在一个函数上,使用时就直接调用绑定的函数:
const boundAddTodo = text => dispatch(addTodo(text))
boundAddTodo(text)
Reducers
指定程序的state怎么根据action来进行响应。
在redux中,应用程序的所有state
都存储为一个单独的对象,reducer
可以确定这个对象的存储形态。
处理actions
reducer
是一个纯函数,它接收先前的state
和一个action
作为参数,并返回新的state
。
(previousState, action) => newState
之所以称为reducer
是因为它其实调用了Array.proptotype.reduce(reducer, ?initialValue)
。reducer必须是纯函数,表示绝对不能再reducer中做如下事情:
- 对参数进行变形
- API调用或路由变形等副作用
- 调用非纯函数,例如
Date.now()
或者Math.random()
给予reducer相同的参数,它应该计算出相同的结果并且返回这个结果,没有副作用,没有API的调用,没有变形,仅仅是一个计算。
function todoApp(state = initialState, action) {
switch (action.type) {
case 'SET_VISIBILITY_FILTER':
return Object.assign({}, state, {
visibilityFilter: action.filter
})
default:
return state
}
}
这里使用了
Object.assign()
复制对象来避免state
被改变,如果使用Object.assign(state, {visibilityFilter: action.filter}}
也是错误的:第一个参数会被改变。所以必须提供一个空对象作为第一个参数。也可以用ES6的解构复制,像这样:{...state, {visibilityFilter: action.filter}}
需要有一个
default
时要返回的情况,因为可能会有别的不确定的action,所以这里默认返回了原来的state
。
两个reducer
可以通过combineReducers()
结合:
const todoApp = combineReducers({
visibilityFilter,
todos
})
Store
store
的用途:
- 存储应用程序的
state
- 通过
getState()
来获取state
- 通过
dispatch(action)
来更新state
- 通过
subscribe(listener)
注册监听者 - 通过
subscribe(listener)
返回的函数来注销监听者 要注意的是一个应用程序中最好只有一个store
。当想要拆分数据逻辑时,可以用reducer composition
而不是创建很多store
let store = createStore(todoApp)
createStore()
可以有第二个参数,作为state
的初始值传入。
Data Flow
redux遵循严格的单向数据流(strict undirectional data flow)
意味着一个应用程序中所有的数据遵循相同的生命周期模式,使程序逻辑更加可预测并且易于理解。也支持数据规范化,这样就不会存在多个相同数据的副本。
redux的数据生命周期遵循以下4步:、
- 调用
store.dispatch(action)
来派发action
store
调用定义好的reducer
来响应action
- 总
reducer
会组合多个reducer
的输出形成单个状态树 store
会接收reducer
返回的状态树并存储起来
与React结合
首先是展示组件和容器组件的区别:
展示组件 | 容器组件 | |
---|---|---|
作用 | 决定组件的外观 | 决定组件的作用(数据获取,状态更新) |
与redux的联系 | 无 | 有 |
如何获取数据 | 从props 传入 |
通过监听redux的state |
如何改变数据 | 调用props 的回调 |
dispatch action |
大部分组件应该都是展示组件,但是也需要容器组件来将组件和redux的store
联系起来。但是并不意味着容器组件应该在组件树顶部。
connect()
提供了很多有用的优化来防止不必要的重复渲染,(其中的一点就是不必去定制shouldComponentUpdate
方法)
mapStateToProps
:决定了怎么将当前的redux store转换为想包裹的展示组件的props
mapDispatchToProps
:可以接收dispatch()
方法并且要注册到展示组件想要注册的回调
别忘了最外围还有一个<Provider></Provider>
组件传递store
<Provider store={store}>
<App />
</Provider>