概念
-
JS的状态容器,提供可预测化的状态管理
-
工作流程
- Viwe --dispatch--> Actions --middleware--> Reducer --> Store --subscribe--> View
- Actioss:对象,type属性描述对状态进行怎样的操作
- Reducer:函数,操作状态并返回新的状态
- Store:存储状态的容器,JS对象
- View:视图,HTML页面
- 核心API
// 1、创建store的状态容器
const store = Redux.createStore(reducer);
// 2、处理状态的reducer函数
function reducer(state = initialState,action){}
// 3、获取状态
store.getState();
// 4、订阅状态
store.subscribe(function(){});
// 5、触发Action
store.dispatch({type: 'description...'});
React + Redux
- 作用
在React中组件通信的数据流是单向的, 顶层组件可以通过props属性向下层组件传递数据, 而下层组件不能向上层组件传递数据,要实现下层组件修改数据,需要上层组件传递修改数据的方法到下层组件.当项目越来越大的时候,组件之间传递数据变得越来越困难.使用Redux管理数据, 由于Store独立于组件,使得数据管理独立于组件, 解决了组件与组件之间传递数据困难的问题。
- react-redux模块
- Provider:将我们创建出来的store放在一个全局的,组件够得着的地方
ReactDOM.render(
<Provider store={store}><Counter></Provider>,
document.getElementById('root')
)
- connect:会帮助我们订阅store 当store中的状态发生更改的时候 会帮助我们重新渲染组件;可以让我们获取store中的状态、dispatch 方法,将状态和方法通过组件的props属性映射给组件
function Counter({count, add}){
return <div>
<button onClick={add}>++</button>
<span>{count}</span>
</div>
}
const mapStateToProps = state => ({
count: state.count
})
const mapDispatchToProps = dispatch => ({
add(){
dispatch({type: 'add'})
}
})
export default connect(mapStateToProps, mapDispatchToProps)(Counter)
- bindActionCreators简化代码
import { bindActionCreators } from 'redux'
import * as counterActions from './counter'
...
mapDispatchToProps = dispatch => bindActionCreators(counterActions, dispatch)
export const add = (payload) => ({type: 'add',payload})
...
中间件
-
允许我们扩展redux应用程序的函数
-
使用案例
- logger
export default store => next => action => {
console.log(store)
console.log(action)
next(action)
}
- store
import { createStore, applyMiddleware } from 'redux'
import { RootReducer } from './reducers/root.reducer'
import { logger } from './middlewares/logger'
// 其他中间件
import { test } from './middlewares/test'
// applyMiddleware用来注册中间件
createStore(RootReducer, applyMiddleware(logger, test))
- thunk
export default ({dispatch}) => next => action => {
if(typeof action === 'function'){
return action(dispatch)
}
next(action)
}
// 使用案例
export const add_async = () => dispatch => {
setTimeout(()=>{ dispatch(add())}, 2000)
}
源码实现
- createStore
function createStore (reducer, preloadedState) {
var currentState = preloadedState;
var currentListeners = [];
function getState(){
return currentState;
}
function dispatch(action){
currentState = reducer(currentState, action)
for (var i = 0; i < currentListeners.length; i++){
var listener = currentListeners[i];
listener();
}
}
function subscribe(listener) {
currentListeners.push(listener);
}
return {
getState,
dispatch,
subscribe,
}
}
- applyMiddleware
function applyMiddleware(...middlewares){
return function(createStore){
return function(reducer, preloadedState){
var store = createStore(reducer, preloadedState);
var middlewareAPI = {
getState: store.getState,
dispatch: store.dispatch,
}
var chain = middlewares.map(middleware => middleware(middlewareAPI))
var dispatch = compose(...chain)(store.dispatch)
return {
...store,
dispatch,
}
}
}
}
function compose(){
var func = [...arguments];
return function(dispatch){
for (var i = func.length-1; i>=0; i--){
dispatch = func[i](dispatch)
}
return dispatch
}
}
- bindActionCreators
function bindActonCreators (actionCreators, dispatch){
var boundActionCreator = {};
for(var key in actionCreators){
(function(key){
boundActionCreators[key] = function(){
dispatch(actionCreators[key]())
}
})(key)
}
return boundActionCreators;
}
- combinReducers
function combinReducers(reducers){
var reducerKeys = Object.keys(reducers);
for(var i = 0; i < reducerKeys.length; i++){
var key = reducerKeys[i];
if(typeof reducers[key] !== 'function') throw new Error('')
}
return function (state, action) {
var nextState = {};
for(var i = 0; i < reducers.length; i++){
var key = reducers[i];
var reducer = reducers[key];
var preState = state[key];
nextState[key] = reducer(preState, action);
}
return nextState;
}
}
Immutable
实现了结构共享,当我们更新一个节点,只有几个节点需要被重新创建。在添加、修改、删除操作后,我们避免了将 map 中所有值拷贝一遍,所以特别是在数据量较大时,这些操作相比Object.assign有明显提升。