共计 3356 个字符,预计需要花费 9 分钟才能阅读完成。
一、redux 应用
redux 应用和之前的 useReducer 应用比拟相似(详情请看 重学 react——context/reducer 一文)
// store.ts
import {createStore, applyMiddleware, combineReducers} from 'redux';
import logger from 'redux-logger'; // 中间件
import thunk from 'redux-thunk'; // 中间件
export interface IState {
name: string,
age: number,
sons: any[]}
export const state: IState = {
name: 'lihaixing',
age: 32,
sons: []};
export type Action = {
type?: string;
data?: any;
};
export function reducer(state: IState | undefined, action: Action) {if (!action.type && !action.data) {
return {
...state,
...action
};
}
switch (action.type) {
case 'update':
return {
...state,
...action.data
};
default:
return state;
}
}
// createStore 与 useReducer 相似
export const store = createStore(reducer, state, applyMiddleware(logger, thunk));
// contaner.tsx
import React, {useReducer} from 'react';
// react-redux 的作用和 react 的 context 相似
import {Provider} from 'react-redux';
import {store} from './store';
import Com1 from './comp1'
import Com2 from './comp2'
const IndexView = () => {return <Provider store={store}>
<Com1 />
<Com2 />
</Provider>
};
export default IndexView;
// com1.tsx
import React, {useContext} from 'react';
import {IState} from './index';
// connect 和 useContext 的作用相似
import {connect} from 'react-redux';
const IndexView = (props: any) => {const {name, age, sons} = props.state;
const {update, asyncUpdate} = props;
const setAge = () => {// dispatch({type: 'update', data: {age: age + 1}});
update({age: age + 1});
};
const setSons = () => {// setTimeout(()=>{// update({sons: [...sons, 1]});
// })
asyncUpdate({sons: [...sons, 1]});
};
return <div>
{name} <br/>
{age} <br/>
{sons} <br/>
<button onClick={setAge}> 按钮 age</button>
<button onClick={setSons}> 按钮 sons</button>
</div>;
};
const mapStateToProps = (state: IState) => ({state});
const mapDispatchToProps = {update: (data: any) => ({type: 'update', data}),
// 异步返回的是函数
asyncUpdate: (data: any) => (dispatch: any) => {setTimeout(() => {dispatch({type: 'update', data});
},1000);
}
};
// 不传第二个参数,props 会有 dispatch
export default connect(mapStateToProps, mapDispatchToProps)(IndexView);
从上述咱们能够将 redux 和 useReducer/useContext 作比照
重学 react——context/reducer
二、手写 Redux
1、createStore
export function createStore(reducer: any, state: any, enhancer?: any) {if (!!enhancer) {return enhancer(createStore)(reducer, state);
}
let currentState: any = state;
const currentListener: any[] = [];
function getState() {return currentState;}
function dispatch(action: any) {currentState = reducer(currentState, action);
currentListener.forEach((v) => v());
return action;
}
function subscribe(cb: any) {currentListener.push(cb);
}
return {
getState,
dispatch,
subscribe
};
}
2、中间件
export function applyMiddleware(...middlewares: any) {return (createStore: any) => {return (reducer: any, state: any) => {const store = createStore(reducer, state);
let dispatch = store.dispatch;
const midApi = {
getState: store.getState,
dispatch: (...arg: any) => dispatch(...arg)
};
/**
* 太难了,写不上来了
* @type {any[]}
*/
const chains = middlewares.map((mw: any) => mw(midApi));
// 强化 dispatch 按程序执行
dispatch = compose(...chains)(dispatch);
console.log(dispatch)
return {
...store,
dispatch
};
};
};
}
// 聚合函数 f3(f2(f1(arg)))
// const f1=(x)=>x;
// const f2=(x)=>2*x;
// const f3=(x)=>3*x;
export function compose(...funcs: any) {if (funcs.length === 1) {return funcs[0];
}
return funcs.reduce((left: any, right: any) => (...args: any) => right(left(...args)));
}
// 本人写一个中间件
function logger({getState, dispatch}: {getState: any, dispatch: any}) {return (dispatch: any) => (action: any) => {console.log(action.type + '执行了');
return dispatch(action);
};
}
function thunk({getState, dispatch}: {getState: any, dispatch: any}) {return (dispatch: any) => (action: any) => {if (typeof action === 'function') {return action(dispatch, getState);
}
return dispatch(action);
};
}
正文完