像vue2一样,当全局多个组件更享同一组状态的时候,就会用到vuex,数据的集中式管理方式,那么,react 中,当遇到项目中,组件共享状态数据比较多,组件和组件之间的数据通信比较复杂,该如何入理呢?接下来,就让我们由浅入深的展开了解,react 的集中数据管理方式。
一:设计思想
试图和状态是一一对应的
所有的状态都保存在一个对象里面
二:基本概念&API
store
store 是保存数据的地方,整个应用只有一个store,redux 提供了createStore这个函数,用来生成store
import { createStore } from 'redux'
const store = createStore(fn)
createStore 接受另一个函数作为参数,返回新的store.
state
store包含所有对象,如果要得到某个时点的数据,就要对
如果想得到某个时点的数据,就要对 Store 生成快照。这种时点的数据集合,就叫做 State。
当前时刻的 state,可以通过store.getState()拿到。
redux 规定,一个state 对应一个view,只要stats相同view就相同。
import {createStore} from 'redux'
let store = createStore(fn)
let state = store.getState()
action
state的变化,会导致view 变化,但是用户接触不到state,只能通过view去改变state,Action 就是 View 发出的通知,表示 State 应该要发生变化了。
action 是一个对象,其中type是必须的,表示action的名称
const action = {
type: 'ADD_TODO',
payload: 'Learn Redux'
};
可以理解为action是描述当前方式的事情,是改变state的唯一方式,就是使用 Action。它会运送数据到 Store。
store.dispatch()
store.dispatch()是view发送action的唯一方式。
import {createStore} from 'redux'
const store = createStore(fn)
store.dispatch({
type: 'ADD_TODO',
payload: 'Learn Redux'
})
reducer
store收到action以后,必须要给出一个新的state,这样view 才会发生变化,这种 State 的计算过程就叫做 Reducer。reducer 是一个纯函数,会接受当前state 和action 两个参数。然后返回一个新的state
const reducer = function(state,action){
return new_state;
}
const defaultstate = 0
const reducer = function(state:defaultstate,action){
switch(action.type){
case 'ADD':
return state + action.payload;
default:
return state
}
}
const state = reducer(1,{
type:'ADD',
payload:2
})
reducer不用像上边这样手动调用,store.dispatch 发送过来一个新的action,就会自动调用reducer,得到新的stats。
纯函数
不能改写参数。
不能调用系统 I/O 的API
不能在函数中使用Date.now()或者Math.random()等不纯的方法
由于reducer是纯函数,就可以保证同样的state必须有同样的view,但正是因为这一点,reducer函数内不能随便改变state,必须返回一个全新的对象
// state 是一个对象
function reducer(state,action){
return Object.assign({},state,{thingToChange}}
}
// state 是一个数组
function reducer(state,action){
return [...state,newItem]
}
reducer 拆分
reducer 函数负责生成state,由于整个应用只有一个state对象,包含所有数据,对于大型应用来说,这个state必然十分庞大,导致reducer 函数也十分庞大。
function reducer(state={},action){
const { type, payload } = action;
switch (type) {
case ADD_CHAT:
return object.assign({},state,{
chatLog:state.chatLog.concat(payload)
});
case CHANGE_STATUS:
return Object.assign({}, state, {
statusMessage: payload
});
case CHANGE_USERNAME:
return Object.assign({}, state, {
userName: payload
});
default: return state;
}
Redux 提供了一个combineReducers方法,用于 Reducer 的拆分。你只要定义各个子 Reducer 函数,然后用这个方法,将它们合成一个大的 Reducer。
import { combineReducers} from 'redux'
const chatReducer = combineReducers({
chatLog,
statusMessage,
userName
})
export default todoApp;
综上所属,我们了解到了redux的基本概念,和工作原理:用户发起action,reducer 函数算出新的state,view 重新渲染。
中间件
但是,又一个关键问题没有解决,异步操作怎么办?action 发起后,reducer立即返回state,这叫同步操作,actions 发起后,reducers 过一段时间在返回state这叫异步操作。
中间件的使用
import {applyMiddleware,createStore} from 'redux'
import createLogger from 'redux-logger';
const logger = createLogger();
const store = createStore(reducer,{
applyMiddleware(logger)
})
异步操作的基本思路
操作发起时的 Action
操作成功时的 Action
操作失败时的 Action
操作开始时,送发一个Action,触发 State 更新为"正在操作"状态,View 重新渲染
操作结束后,再送出一个 Action,触发 State 更新为"操作结束"状态,View 再一次重新渲染
redux-thunk 中间件
异步操作用户需要触发两个action,第一个是用户操作前发起,第二个是在用户操作结束后发起,如何才能在操作结束时,系统自动送出第二个Action呢?
redux-saga
redux-promise
react-redux
connect()
react-redux 提供connect 方法,用户UI组件生成容器组件。
import {connect} from 'reat-redux'
const VisibleTodoList = connect()(TodoList)
上面代码中,TodoList 是UI组件,VisibleTodoList就是由react-redux 通过connect方法自动生成的容器组件。
但是,因为没有定义业务逻辑,上面这个容器组件毫无意义,只是 UI 组件的一个单纯的包装层。为了定义业务逻辑,需要给出下面两方面的信息。
(1)输入逻辑:外部数据(既state 对象)如何转成UI组件的参数。
(2)输出逻辑:用户发出的动作如何变为action对象,从UI组件传出去。
因此,connect 方法的完整API如下图所示:
import { connect } from 'react-redux';
const VisibleTodoList = connect(
mapStateToProps,
mapDispatchToProps
)(TodoList)
mapStateToProps
mapStateToProps 第一个参数,总是state对象,还可以有第二个参数,代表容器组件的props 对象。
const mapStateToProps = (state) => {
return {
todos: getVisibleTodos(state.todos, state.visibilityFilter)
}
}
const getVisibleTodos = (todos,filter) => {
case 'SHOW_ALL':
return todos
case 'SHOW_COMPLETED':
return todos.filter(t => t.completed)
case 'SHOW_ACTIVE':
return todos.filter(t => !t.completed)
default:
throw new Error('Unknown filter: ' + filter)
}
mapDispatchToProps
mapDispatchToProps是connect函数的第二个参数,用来建立 UI 组件的参数到store.dispatch方法的映射。也就是说,它定义了哪些用户的操作应该当作 Action,传给 Store。它可以是一个函数,也可以是一个对象。
如果mapDispatchToProps是一个函数,会得到dispatch和ownProps(容器组件的props对象)两个参数。