看到标题,你会想到什么???有什么解决方案
react
咱们来经过class版本往react hook版本一步步递进
咱们来经过使用复选框点击事件来看结果redux
import { ToggleState } from '../store/reducers/toggle';
import { RootState } from '../store/reducers';
type Props = ToggleState & typeof action;
class Toggle extends React.Component<Props, any> {
render(){
const { ui, toggleSwitch } = this.props;
return (
<div>
<div>{JSON.stringify(ui)}</div>
<input
type="checkbox"
value={ui.toggle ? 'true': 'false'}
onChange={(e)=>toggleSwitch(e)}
/>
</div>
);
}
}
const mapStateToProps = (state: RootState):ToggleState => state.toggle;
export default connect(mapStateToProps, action)(Toggle);
复制代码
import action from '../store/actions/toggle'
import { ToggleState } from '../store/reducers/toggle';
import { RootState } from '../store/reducers';
type Props = typeof action;
const Toggle2 = ({toggleSwitch}:Props) => {
const { ui }: ToggleState = useSelector((state: RootState):ToggleState => state.toggle);
return (
<div>
<div>{JSON.stringify(ui)}</div>
<input
type="checkbox"
value={ui.toggle ? 'true': 'false'}
onChange={(e)=>toggleSwitch(e)}
/>
</div>
);
}
export default connect(null, action)(Toggle2);
复制代码
咱们将class组件替换成了函数组件,其余的不变
还不是咱们想要的结果,继续优化咯~~~数组
type Props = typeof action;
// 使用 useSelector hook,咱们能够读取咱们的状态。
// useDispatch hook 让咱们执行 redux 操做
// 咱们能够在任何事件监听器中调用 dispatch 函数。
const Toggle3 = () => {
const { ui }: ToggleState = useSelector((state: RootState):ToggleState => state.toggle);
const dispatch = useDispatch();
return (
<div>
<div>{JSON.stringify(ui)}</div>
<input
type="checkbox"
value={ui.toggle ? 'true': 'false'}
onChange={(e: ChangeEvent<HTMLInputElement>)=>dispatch({type: 'toggleSwitch', value: e.currentTarget.checked})}
/>
</div>
);
}
export default Toggle3;
复制代码
固然这边我有其余class组件例子使用了redux,咱们但愿整改是一点点改掉,因此确定会出现一部分使用react hook函数组件, 一部分使用class组件promise
let reducers: ReducersMapObject<ReducerState, AnyAction> = {
counter1,
counter2,
toggle
}
export type RootState = {
[P in keyof typeof reducers]: ReturnType<typeof reducers[P]>
}
复制代码
使用 useSelector 获取到对应的store状态使用, useDispatch 帮助咱们获取到store的dispatch方法,帮助咱们调用对应的reducerbash
// ====== ToggleReducer组件 ======
import { ContextParam, AppContext } from './test';
const ToggleReducer = () => {
const { state, dispatch } = useContext<ContextParam>(AppContext);
const { ui } = state;
return (
<div>
<div>{JSON.stringify(ui)}</div>
<input
type="checkbox"
value={ui.toggle ? 'true': 'false'}
onChange={(e: ChangeEvent<HTMLInputElement>)=>dispatch!({type: 'toggleSwitch', value: e.currentTarget.checked})}
/>
</div>
);
}
export default ToggleReducer;
// ====== ToggleReducer1组件 ======
import { ContextParam, AppContext } from './test';
const ToggleReducer1 = () => {
const { state, dispatch } = useContext<ContextParam>(AppContext);
const { ui } = state;
return (
<div>
<div>{JSON.stringify(ui)}</div>
<input
type="checkbox"
value={ui.toggle ? 'true': 'false'}
onChange={(e: ChangeEvent<HTMLInputElement>)=>dispatch!({type: 'toggleSwitch', value: e.currentTarget.checked})}
/>
</div>
);
}
export default ToggleReducer1;
// ====== Test组件 ======
export interface ContextParam {
state?: any,
dispatch?: Dispatch<AnyAction>
}
export const AppContext: Context<ContextParam> = React.createContext({});
const Test = () => {
const [state, dispatch] = useReducer(reducers, {
ui:{
toggle: false,
sum: 0
}
});
return (
<AppContext.Provider value={{state, dispatch}}>
<ToggleReducer />
<ToggleReducer1 />
</AppContext.Provider>
);
}
复制代码
使用上useContext,useReducer 混合以后,效果可见:异步
说到react hook替换到老式的redux了,若是到后期了,全部的都得改掉,那么中间件没提供方案怎么办,咱们能够手写个,也很简单的呀~ide
咱们使用 useLogger 模拟redux-logger中间件功能函数
type Reducer<S, A> = (prevState: S, action: A) => S;
/**
* useLogger 模拟redux-logger中间件
* @param reducer
* @param initState
*/
function useLogger(reducer: Reducer<StateParam, any>, initState: StateParam):[StateParam, any] {
const [state, dispath] = useReducer(reducer, initState);
function loggerDispatch(action:any) {
console.log('修改以前状态:', state);
dispath(action);
}
useEffect(() => {
console.log('修改以后状态:', state);
}, [state])
return [state, loggerDispatch];
}
复制代码
调用方式优化
function App() {
const initState: StateParam = { number: 0 };
const [state, dispath] = useLogger(reducer, initState)
return (
<div>
<div>number: {state.number}</div>
<button onClick={() => dispath({ type: 'INCREMENT' })}>+</button>
<button onClick={() => dispath({ type: 'DECREMENT' })}>-</button>
</div>
)
}
复制代码
中间件的操做基本上是封装原有的store.dispatch ui
咱们也想异步加载中间件,咱们这边我就用useThunk来模拟redux-thunk中间件
/**
* useThunk 模拟redux-thunk中间件
* thunk的action调用接收2个参数 , 第一个是dispatch,第二个是getState
* @param reducer
* @param initState
*/
function useThunk(reducer: Reducer<StateParam, any>, initState: StateParam):[StateParam, any] {
const [state, dispath] = useLogger(reducer, initState);
function thunkDispatch(action: any) {
if (action && typeof action === 'function') {
return action(thunkDispatch, () => state);
}
return dispath(action);
}
return [state, thunkDispatch];
}
复制代码
调用方式
function App() {
const initState: StateParam = { number: 0 };
const [state, dispath] = useThunk(reducer, initState)
return (
<div>
<div>number: {state.number}</div>
<button onClick={() => dispath({ type: 'INCREMENT' })}>+</button>
<button onClick={() => dispath({ type: 'DECREMENT' })}>-</button>
<button onClick={() => dispath(() => {
setTimeout(() => {
dispath({ type: 'INCREMENT' })
}, 1000);
})}>thunkplus</button>
</div>
)
}
复制代码
咱们再来用usePromise模拟下redux-promise
function usePromise(reducer: Reducer<StateParam, any>, initState: StateParam):[StateParam, any] {
const [state, dispath] = useLogger(reducer, initState);
function promiseDispatch(action: any) {
if (action && typeof action.then === 'function') {
action.then(promiseDispatch)
}
dispath(action);
}
return [state, promiseDispatch];
}
复制代码
调用方式
function App() {
const initState: StateParam = { number: 0 };
const [state, dispath] = usePromise(reducer, initState)
return (
<div>
<div>number: {state.number}</div>
<button onClick={() => dispath({ type: 'INCREMENT' })}>+</button>
<button onClick={() => dispath({ type: 'DECREMENT' })}>-</button>
<button onClick={() => dispath(new Promise(resolve => {
setTimeout(() => {
resolve({ type: 'INCREMENT' })
}, 1000);
})
)}>promiseplus</button>
</div>
)
}
复制代码
咱们挑了几个常见简单的中间件入手实践了一波,简单demo已经调研,可使用到项目中去了,你们有什么看法能够发评论区你们一块儿讨论哈!感谢你的阅读,比心~~~~