Redux 是一款状态管理库,并且提供了react-redux 库来与React 亲密配合, 但是总是傻傻分不清楚这2者提供的API 和相应的关系。这篇文章就来理一理。
Redux
Redux 三大核心
Redux 的核心由三部分组成:Store ,Action ,Reducer 。
-
Store : 是个对象,贯穿你整个应用的数据都应该存储在这里。
-
Action : 是个对象,必须包含type 这个属性,reducer 将根据这个属性值来对store 进行相应的处理。除此之外的属性,就是进行这个操作需要的数据。
-
Reducer : 是个函数。接受两个参数:要修改的数据(state) 和 action 对象。根据action.type 来决定采用的操作,对state 进行修改,最后返回新的state 。
===== Store =====
{
todos: [],visibilityFilter: 'SHOW_ALL'
}
===== Action =====
{
type: 'ADD_TODO',text: 'Build my first Redux app'
}
===== Reducer =====
const todos = (state = [],action) => {
switch (action.type) {
case 'ADD_TODO':
return [
...state,{
id: action.id,text: action.text,completed: false
}
]
default:
return state
}
}
Redux核心之间的关系
在上一部分,我们提到了,我们触发action → reducer来处理 。这就是二者之间的关系。那么我们怎么触发action 呢?Store 这个对象提供了dispatch方法 → 触发action 。dispatch 方法接受action 对象作为参数。因此,我们可以了解三者之间的关系:
`store` ?? `dispatch` ?? `action` ?? `reducer`
Store
我们通过redux 提供的createStore 这个方法来创建一个Store 。它接受对store 进行处理的reducer 作为参数。
Store 有三个方法:
-
getState :用来获取store 里面存储的数据。
-
dispatch : store 里的数据不能直接修改,只能通过触发action 来进行修改,这个方法就是用来触发action 。
-
subscibe :订阅store 改变时,要进行的操作。比如在react 中,当store 改变时,我们需要调用render 方法对视图进行更新。
const store = createStore(reducer);
store.getState(); // { todos: [],visibilityFilter: 'SHOW_ALL' }
store.dispatch({
type: 'ADD_TODO',text: 'Build my first Redux app'
});
store.subscibe(() => {
console.log(store.getState());
});
Reducer
我们可以将对store 的操作,写在一个reducer 中,比如:
function todoApp(state = initialState,action) {
switch (action.type) {
case SET_VISIBILITY_FILTER:
return Object.assign({},state,{
visibilityFilter: action.filter
})
case ADD_TODO:
case TOGGLE_TODO:
return Object.assign({},{
todos: todos(state.todos,action)
})
default:
return state
}
}
可以看到这个reducer 对store 的visibilityFilter 和todos 的两部分数据进行了处理。随着应用的复杂,如果我们把对所有数据的处理,都写在一个reducer 中,那么它会变得很冗杂。如果我们将对每一部分的数据的处理,写在一个单独的reducer 中,它接受该部分的数据作为state 。那么整个reducer 会变得整洁和清晰。
因此,redux 为我们提供了combineReducer 这个API ,帮助我们分开书写reducer , 并且最终把这些reducer 给集合到一个根reducer 中。
// 对todos进行处理
function todos(state = [],action) {
switch (action.type) {
case ADD_TODO:
return [
...state,{
text: action.text,completed: false
}
]
default:
return state
}
}
// 对 visibilityFilter 进行处理
function visibilityFilter(state = SHOW_ALL,action) {
switch (action.type) {
case SET_VISIBILITY_FILTER:
return action.filter
default:
return state
}
}
// 生成 root reducer
function todoApp(state = {},action) {
return {
visibilityFilter: visibilityFilter(state.visibilityFilter,action),todos: todos(state.todos,action)
}
}
// 创建store
const store = createStore(todoApp)
react-redux
上一部分我们介绍了redux 的核心。可以看到,redux 是独立的应用状态管理工具。它是可以独立于react 之外的。如果我们需要在react 当中运用它,那么我们需要手动订阅store 的状态变化,来对我们的react 组件进行更新。那么react-reudx 这个工具,就帮我们实现了这个功能,我们只需对store 进行处理,react 组件就会有相应的变化。
这个工具主要提供两个API :
connect
现在我们有了store ,那么我们怎么才能在我们的组件中对它们进行操作呢?connect 就为提供了这个功能。它接受mapStateToProps ,mapDispatchToProps 等作为参数。比如在我的TodoList 这个组件中需要用到todos 这部分数据,那么我完善mapStateToProps 这个函数,它接受store 中的state 作为参数,返回一个对象,属性就是state 中我们需要的数据:
const mapStateToProps = state => {
return {
todos: state.todos
}
}
mapStateToProps 就将我们的state 转换为了props 对象。
同样的,我们可能需要在组件中对state 进行处理。mapDispatchToProps 就是帮助我们在组件中通过props 调用dispatch 来触发action 的:
const mapDispatchToProps = dispatch => {
return {
onTodoClick: id => {
dispatch(toggleTodo(id))
}
}
}
最后我们调用connect 这个方法,将mapStateToProps , mapDispatchToProps 生成的props 注入到需要使用它的组`中:
const VisibleTodoList = connect(
mapStateToProps,mapDispatchToProps
)(TodoList)
这样,我们在TodoList 这个组件中,就能直接通过props.todos 获取到todos 中的数据, 通过props.onTodoClick 对todos 进行处理。
provider
上面我们调用connect 时,在mapStateToProps 和 mapDispatchToProps 我们分别用到了store 的state 和dispatch 。但是在组件中的store 是哪里凭空冒出来的呢?
provider 就是来解决这个事的。Provider 使它的子孙在调用connect 方法时,都能获取到store 。
const VisibleTodoList = connect(
mapStateToProps,mapDispatchToProps
)(TodoList)
const App = () => (
<div>
<AddTodo />
<VisibleTodoList />
<Footer />
</div>
)
<Provider store={store}>
<App />
</Provider>
这样,Provider 的子孙组件都能在调用connect 时获取到store 。
总结
(编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|