在使用react的过程当中,用redux来管理应用中的状态,使应用流更清晰的同时也会有小小的疑惑,好比reducer在redux中时怎么发挥做用的,为何只要写好reducer,和dispatch特定action配合,store的状态就会更新了,而react组件又是如何和store的状态产生关系的,为何随着store状态的更新,react组件会被自动更新,下面就从redux的源码开始来总结下这其中的原因~react
redux是继承自flux体系,但它放弃了dispatcher,无需使用 event emitters(事件发送器)(在dispatcher中特定action逻辑里触发事件,组件里监听事件),而使用纯 reducer来代替,那么reducer是如何被调度的,又是如何影响状态更新的,不妨经过源码的逻辑来了解和加深一下~redux
reducer一般是由咱们本身来写,在调用createStore
函数生成store时来传入这个reducer
,后续调用store
的dispatch
方法来触发action
时,则reducer
函数会自动被调用来解析actin
更新state
,这一切的核心都在crateStore
方法中数组
export default function createStore(reducer, preloadedState, enhancer) {
...
let currentReducer = reducer
let currentState = preloadedState
let currentListeners = []
let nextListeners = currentListeners
let isDispatching = false
function getState() {
...
}
function subscribe(listener) {
...
}
function dispatch(action) {
...
}
function replaceReducer(nextReducer) {
...
}
function observable() {
...
}
return {
dispatch,
subscribe,
getState,
replaceReducer,
[$$observable]: observable
}
}
复制代码
能够看到createStore方法返回一个属性集合,咱们所调用的redux的相关方法都是定义在createStroe方法内部,最后被经过这个属性集合中暴露出来,如处理action的dispath方法,同currentReducer,currentState是createStore方法中的私有变量,由dispath,subscribe,getState等方法共享,咱们设置的reducer,redux的state状态,以及state改变以后应该自动触发哪些函数,这些逻辑都是经过这几个内部变量和函数来实现的,下面先来看一下几个核心方法,由咱们直接接触到的dispath开始~bash
function dispatch(action) {
...
try {
//将flag置为true,代表处于分发逻辑中
isDispatching = true
//currentReducer即为函入的reducer函数,这里会自动调用currentReducer函数,并将返回值赋给currentState
currentState = currentReducer(currentState, action)
} finally {
isDispatching = false
}
//调用监听函数
const listeners = (currentListeners = nextListeners)
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i]
listener()
}
return action
}
复制代码
能够看到,在dispath中调用reducer方法处理action以后,返回值(新的state)会直接赋值给currentState
,由此能够推测currentState
应该就是getState
要返回的状态ide
function getState() {
if (isDispatching) {
throw new Error(
...
)
}
return currentState //直接返回currentState内部变量
}
复制代码
function subscribe(listener) {
if (typeof listener !== 'function') {
throw new Error(...)
}
if (isDispatching) {
throw new Error(
...
)
}
let isSubscribed = true
...
nextListeners.push(listener)
return function unsubscribe() {
...
}
复制代码
在subscribe中,传入的listener函数会被添加进nextListeners数组中,当dispatch方法被调用时自动触发,react-redux的状态更新时,UI自动更新的特性是经过subscribe来实现的函数
首先,设想咱们不知道react-redux库来链接react和redux,来试一下单纯的经过redux做为react组件的状态管理器ui
//首先,建立一个reducer处理函数
function todoApp(state = initialState, action) {
switch (action.type) {
case SET_VISIBILITY_FILTER:
return ...
case ADD_TODO:
return ...
default:
return state
}
}
//建立store
const store = createStore(
todoApp
);
复制代码
要在各组件之间共享变量store有两种方式可取,一种是经过props共享,一种是经过context实现,其中props共享变量须要每一层组件之间层层传递该变量,这样作无疑很麻烦,尤为是组件以前嵌套层次比较深的时候,因此咱们这里用react的context属性来实现共享storethis
class App extends Component {
getChildContext() {
return {
store: this.props.store
};
}
render() {
return <ToDoList />;
}
}
App.childContextTypes = {
store: React.PropTypes.object
}
复制代码
class VisibleTodoList extends Component {
componentDidMount() {
const { store } = this.context;
this.unsubscribe = store.subscribe(() =>
this.forceUpdate()
);
}
render() {
const props = this.props;
const { store } = this.context;
const state = store.getState();
// ...
}
}
VisibleTodoList.contextTypes = {
store: React.PropTypes.object
}
复制代码
如上所示,在须要获取store状态的组件中,在组件加载完成后须要获取关心得context的变量值store,同时订阅事件,当store的状态变化后触发组件自己的强制更新,而render中只需用store.getState
获取store的状态值便可spa
上例中写了一个组件的实现还好,但当组件多的时候,每一个组件都需写本身的获取context,订阅事件强制更新自身,获取state,这样的样板代码,实际是不必的,彻底能够把这部分抽象出来,而react-redux就帮咱们作了这些,让咱们省去了自定义context和订阅事件,获取state等操做code
要利用redux
来管理状态,须要在祖先组件的context
属性中指定store
,而这必定式化的操做能够有react-redux
库中的Provider来完成
,示例以下
<Provider store={store}>
<App />
</Provider>
复制代码
上节中提到过,要实现store的状态更新后能自动更新react组件,则组件需在挂载后调用store
的subscribe
方法来订阅store
中状态的变动,而这块儿样板代码则能够由react-redux
库中的connect
建立的容器组件来自动完成
class TodoList extends Component {
render(){
...
}
}
const mapStateToProps = state => {
return {
todos: getVisibleTodos(state.todos, state.visibilityFilter)
}
}
const mapDispatchToProps = dispatch => {
return {
onTodoClick: id => {
dispatch(toggleTodo(id))
}
}
}
const VisibleTodoList = connect(
mapStateToProps,
mapDispatchToProps
)(TodoList)
复制代码
其中mapStateToProps提供从Redux store state到展现组件的 props的映射 ,mapDispatchToProps接收dispatch方法并提供指望注入到展现组件的 props 中的回调方法。