Redux
1、数据流
2、redux的实现
const createStore = (reducer) => {
let state = {};
let listeners = [];
const getState = () => state;
const dispatch = (action) => (reducer) => {
state = reducer(state, action);
listeners.forEach(fn => fn());
}
let subscribe = (listener) => {
listeners.push(listener);
}
//初始的状态
dispatch({type: '@@CHEN-REDUX});
return { getState, dispatch, subscribe }
}
export {createStore} ;
3、context的使用
在生命周期方法中引用 Context
如果 contextTypes 在组件中定义,下列的生命周期方法将接受一个额外的参数, context 对象:
- constructor(props, context)
- componentWillReceiveProps(nextProps, nextContext)
- shouldComponentUpdate(nextProps, nextState, nextContext)
- componentWillUpdate(nextProps, nextState, nextContext)
- componentDidUpdate(prevProps, prevState, prevContext)
- function(props, context)
childContextTypes中声明类型要不不能用 getChildContext 中取
4、react-redux的实现
Provider 利用context属性可以让所有的子组件来取到store
// render(
// <Provider store={store}>
// <App />
// </Provider>,
// document.getElementById('root')
// )
export class Provider extends React.Component {
static childContextTypes = {
store:PropTypes.object
}
constructor(props, context) {
super(props, context);
this.store = props.store;
}
getChildContext() {
return {store: this.store}
}
render() {
return this.props.children;
}
}
connet 的实现
import React, {PropTypes} from 'react';
//高阶组件
//1.负责接收一个组件,把state里的数据放进去,返回一个组件
//2.数据变化的时候,能够通知组件
function bindActionCreator (creators, dispatch) {
return (...args) => dispatch(creator(...args));
}
function bindActionCreators (creators, dispatch) {
let bound = {};
Object.keys(creators).forEach(v=>{
let creator = creators[v]
bound[v] = bindActionCreator(creator, dispatch)
})
return bound;
}
export const connect = (mapStateToProps = state => state,
mapDispatchToProps = {}) => (WrapComponent) => {
return class ConnectComponent extends React.Component {
static contextTypes = {
store: PropTypes.object
}
constructor(props, context) {
super(props, context);
this.state = {
props: {}
}
}
componentDidMount() {
const {store} = this.context;
store.subscribe(()=>this.update());
this.update();
}
update() {
const {store} = this.context;
//把state传入mapStateToProps,然后返回自己需要的
const stateProps = mapStateToProps(store.getState());
//方法不能直接给,需要dispatch 直接执行addGun()是没有意义的。
//需要addGun = store.dispatch(addGun 才有意义
const dispatchProps = bindActionCreators(mapDispatchToProps, store.dispatch)
this.setState({
props: {
...this.state.props,
...stateProps,
...dispatchProps
}
})
}
render() {
return <WrapComponent {...this.state.props} />
}
}
};
5、中间件
中间件的理解
只有发送 Action 的这个步骤,即store.dispatch()方法,可以添加功能
举例来说,要添加日志功能,把 Action 和 State 打印出来,可以对store.dispatch进行如下改造。
let next = store.dispatch;
store.dispatch = function dispatchAndLog(action) {
console.log('dispatching', action);
next(action);
console.log('next state', store.getState());
}
对store.dispatch进行了重定义,在发送 Action 前后添加了打印功能。这就是中间件的雏形。
中间件就是一个函数,对store.dispatch方法进行了改造,在发出 Action 和执行 Reducer 这两步之间,
中间件的使用
const store = createStore(
reducer,
initial_state,
applyMiddleware(logger)
);
applyMiddlewares() 的实现单个
const createStore = (reducer, enhancer) => {
if (enhancer) {
return enhander(createStore)(reducer);
}
let state = {};
let listeners = [];
const getState = () => state;
const dispatch = (action) => (reducer) => {
state = reducer(state, action);
listeners.forEach(fn => fn());
}
let subscribe = (listener) => {
listeners.push(listener);
}
dispatch({});
return { getState, dispatch, subscribe }
}
export function applyMiddleware (middleware) {
return createStore=>(...args)=>{
const store = createStore(...args);
let dispatch = store.dispatch;
const midApi = {
getState: store.getState,
dispatch: (...args) => dispatch(...args)
}
dispatch = middleware(midApi)(store.dispatch);
return {
...store,
dispatch
}
}
}
多个中间件
export default function applyMiddleware(...middlewares) {
return (createStore) => (reducer, preloadedState, enhancer) => {
var store = createStore(reducer, preloadedState, enhancer);
var dispatch = store.dispatch;
var chain = [];
var middlewareAPI = {
getState: store.getState,
dispatch: (action) => dispatch(action)
};
chain = middlewares.map(middleware => middleware(middlewareAPI));
dispatch = compose(...chain)(store.dispatch);
return {...store, dispatch}
}
}
compose
export function compose (...funcs) {
if (funcs.length == 0) {
return arg => arg;
}
if (funcs.length == 1) {
return funcs[0]
}
return funcs.reduce((ret, item) => (...args) => ret(item(...item)))
}
compost(f1, f2, f3)
f1(f2(f3()))
自己实现一个thunk 感觉就是处理异步的callback
const thunk = ({dispatch, getState})=>next=>action=> {
if (typeof action == 'function') {
return action(dispatch, getState);
}
return next(actions);
}
export default thunk;
使用传入的是active
store.dispatch(function(dispatch){
setTimeout(function(){
dispatch({type: 'INCREMENT'})
}, 5000)
})
理解
const thunk = function({dispatch, getState}){
return function (next) { //dispatch = middleware(midApi)(store.dispatch);
return function (action) {
if (typeof action == 'function') {
return action(dispatch, getState);
}
return next(actions);
}
}
}
let next = store.dispatch;
store.dispatch = function dispatchAndLog(action) {
console.log('dispatching', action);
next(action);
console.log('next state', store.getState());
}
多个连续异步
store.dispatch(function(dispatch){
setTimeout(function(){
console.log('1')
dispatch(function(dispatch) {
setTimeout(function () {
console.log('2')
dispatch({type: 'INCREMENT'})
}, 2000)
})
}, 1000)
})
console.log('0')
redux-promise的源码,就会明白它内部是怎么操作的
export default function promiseMiddleware({ dispatch }) {
return next => action => {
if (!isFSA(action)) {
return isPromise(action)
? action.then(dispatch)
: next(action);
}
return isPromise(action.payload)
? action.payload.then(
result => dispatch({ ...action, payload: result }),
error => {
dispatch({ ...action, payload: error, error: true });
return Promise.reject(error);
}
)
: next(action);
};
}
如果 Action 本身是一个 Promise,它 resolve 以后的值应该是一个 Action 对象,会被dispatch方法送出(action.then(dispatch)),但 reject 以后不会有任何动作;如果 Action 对象的payload属性是一个 Promise 对象,那么无论 resolve 和 reject,dispatch方法都会发出 Action。
使用有两种方式:
第一种穿promise然后返回action
store.dispatch(
new Promise((resolve, reject)=> {
setTimeout(()=> {
console.log(1);
resolve('sss')
}, 2000)
}).then(response => { return {
type: 'INCREMENT',
payload: response
}})
)
一种是在把传入的active的payload生成promise
store.dispatch(
{
type:'INCREMENT',
payload: new Promise((resolve, reject)=> {
setTimeout(()=> {
console.log(1);
resolve('sss')
}, 2000)
}).then(function(data) {
return data;
})
}
)