6.1.7 redux 与react-redux

296 阅读2分钟

1.redux 介绍

   createStore(reducer, [preloadedState], enhancer) 

combineReducers

  rootReducer = combineReducers({potato: potatoReducer, tomato: tomatoReducer})

applyMiddleware:配合thunk

  import thunk from 'redux-thunk'
 store = createStore(reducer, applyMiddleware(thunk))

bindActionCreators

 bindActionCreators(actionCreators, dispatch) 

compose:从右到左来组合多个函数

compose(...functions) 
<Provider store={store}></Provider>

connect

//`options` 设置了 `{ withRef: true }` 才返回被包装的组件实例
connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])
  • redux-thunk :支持 dispatch function,以此让 action creator 控制反转。被 dispatch 的 function 会接收 [dispatch]作为参数,并且可以异步调用它

2.react-redux 用法

创建store

import { createStore } from 'redux';

function counter(state = 0, action) {
  switch (action.type) {
  case 'INCREMENT':
    return state + 1;
  case 'DECREMENT':
    return state - 1;
  default:
    return state;
  }
}


// API 是 { subscribe, dispatch, getState }。
let store = createStore(counter);

store.subscribe(() =>
  console.log(store.getState())
);

store.dispatch({ type: 'INCREMENT' });  // 1
store.dispatch({ type: 'INCREMENT' }); // 2
store.dispatch({ type: 'DECREMENT' }); // 1

Provider 全局引入store

import { Provider } from 'react-redux'
const App = ()=>{
    <Provider store={store}>
     <RouterPage />
    </Provider>
)

connect 获取store数据

function addTodo(state = [], action) {
  switch (action.type) {
    case 'ADD_TODO':
      return state.concat([action.text])
    default:
      return state
  }
}

import { bindActionCreators } from 'redux'

function mapStateToProps(state) {
  return { todos: state.todos }
}

function mapDispatchToProps(dispatch) {
  return bindActionCreators({ addTodo }, dispatch)
}

export default connect(mapStateToProps, mapDispatchToProps)(TodoApp)

3.响应式原理

store可以订阅状态值,状态变化触发connect 函数 的 store.subscribe订阅函数。
connect通过hoc将store的值通过props传给包裹组件,通过setState触发视图更新。

4.react-redux Provider connect源码

Provider

function createContext(defaultValue, calculateChangedBits) {
	var context = {
	        $$typeof: REACT_CONTEXT_TYPE, 
	        _calculateChangedBits: calculateChangedBits,
	        _currentValue: defaultValue, //Provider的value属性
	        _currentValue2: defaultValue,
	        _threadCount: 0, 
	        Provider: null, //提供组件
	        Consumer: null  //应用组件
	      };
	
	      //context.Provider的_context指向context对象
	      context.Provider = {
	        $$typeof: REACT_PROVIDER_TYPE,
	        _context: context
	      };
		  
		  var Consumer = {
		      $$typeof: REACT_CONTEXT_TYPE,
		      _context: context,
		      _calculateChangedBits: context._calculateChangedBits 
		  };
		  context.Consumer = Consumer; // 这样能拿到<Provider>提供的最新值
		  //返回一个context对象  
		  return context;
}

connect

var connect = (mapStatetoProps,mapActionstoProps)=>(WrapperComponent)=>{
    return class Connect extends Component {
    	static contextType = storeContext; // provide定义的context对象
        constructor(props){
            super();
        }
        componentWillMount(){
           const store  = this.context;
           store.subscribe(this._updateProps)
           this._updateProps() // 初始化
        }
        _updateProps= ()=> {
          const store  = this.context;
          // 传入state和props
          var stateProps = mapStatetoProps ? mapStatetoProps(store.getState(),this.props) : {};
          // 传入dispatch和props
          var actionProps = mapActionstoProps ?mapActionstoProps(store.dispatch,this.props) : {}; 
          //整合props,传给接收的组件
          this.setState({
              allProps:{
                    ...stateProps,
                    ...actionProps,
                    ...this.props
                   }
              })
         }

        render() {
             return (
                <div className="Mid">
                     <WrapperComponent {...this.state.allProps}/>
                 </div>
                );
         }
     }

  }	

5.applyMiddleware 源码

image.png

用法:

    store = createStore(reducer, applyMiddleware(mid1, mid2, mid3, ...))
    等同于
    store = applyMiddleware(mid1, mid2, mid3, ...)(createStore)(reducer, null);

applyMiddleware源码:

import compose from './compose';
 
export default function applyMiddleware(...middlewares) {
    return (createStore) => (reducer, initalState) => {
        let store = createStore(reducer, initalState);
        let dispatch = store.dispatch;
        let chain = [];
 
        var middlewareAPI = {
            getState: store.getState,
            dispatch: (action) => dispatch(action)
        };
        chain = middlewares.map( middleware => middleware(middlewareAPI));
        dispatch = compose(...chain)(store.dispatch);  //f1(f2(f3(store.dispatch)))
 
        return {
            ...store,
            dispatch
        };
    }
}
function compose(...funs) {
   return arg => funcs.reduceRight( (composed, cur) => cur(composed), arg)
}
  • logger middleware的源码实现:
export default (store) => next => action => {  //store=middlewareAPI
    console.log('dispatch:', action);
    next(action);  
    // f3(store.dispatch)->f2(f3(store.dispatch))->f1(f2(f3(store.dispatch)))
    console.log('finish:', action);
}
  • redux-thunk 异步action
import thunkMiddleware from 'redux-thunk'
const store = createStore(reducer, applyMiddleware(thunkMiddleware))

const login = (userName) => (dispatch,getState) => {
  dispatch({ type: 'loginStart' })
  request.post('/api/login', { data: userName }, () => {
    dispatch({ type: 'loginSuccess', payload: userName })
  })
}
store.dispatch(login('Lucy'))



function createThunkMiddleware(extraArgument) {
  return ({ dispatch, getState }) => next => action => {
    if (typeof action === 'function') {
      return action(dispatch, getState, extraArgument);
    }

    return next(action);
  };
}

const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;

export default thunk;

参考 www.freesion.com/article/582…

欢迎关注我的前端自检清单,我和你一起成长