React,手写简易redux(一)
本章节会完成一个简易的redux实现
该系列内容会逐步实现简易的redux 使用技术栈:vite+react 该系列感谢@方应杭 的react教学视频
目录
实现reducer
在实现reducer之前,我们先简单使用基本的state操作来实现一个组件之间通信
import React, { useState, useContext } from "react";
import "./App.css";
const appContext = React.createContext(null);
const 张三 = () => {
const {appState,setValue} = useContext(appContext);
function changeAge(e) {
const val = e.target.value;
setValue({ ...appState, age: val });
}
return (
<div>
<p>张三</p>
<div>
<input value={appState.user.age} onChange={changeAge} />
</div>
</div>
);
};
const 李四 = () => <div><p>李四</p>名字:{useContext(appContext).appState.user.name},年龄:{useContext(appContext).appState.user.age}</div>;
const 王五 = () => <div>王五</div>;
const App = () => {
const [appState, setValue] = useState({
user:{
name: "张三",
age: 18,
}
});
const contextValue = { appState, setValue };
return (
<appContext.Provider value={contextValue}>
<div className="container">
<div className="box">
<张三 />
</div>
<div className="box">
<李四 />
</div>
<div className="box">
<王五 />
</div>
</div>
</appContext.Provider>
);
};
export default App;
以上代码的效果是这样: 
上面的代码分别创建了:
- App根组件
- 三个子组件:张三、李四、王五
- 以及一个上下文
appContext - 在App中定义了一个state:appState
我们在<张三>组件中放入一个input组件来修改value值,在李四组件中展示对应的内容。 通过useConnext 建立于数据源联系。以上代码是没问题的,每次setValue时都是一个新对象,视图会对应更新。 但是在实际业务中,会存在大量的state存储,我们要跨组件处理数据的同时,也要指定对应的规范。 接下来,我们尝试将创建新对象这个行为单独出来写一个函数,用函数来代替我们生成新state对象
const reducer = (state,action)=>{
const { type, payload} = action;
switch(type){
case 'changeUser':
return {
...state,
user:{
...state.user,
...payload
},
};
default:
return state
}
}
function changeAge(e) {
const val = e.target.value;
setValue(reducer(appState,{type:'changeAge',payload:{age:val}}));
}
以上内容已经初步有点reducer的样子。上面的代码表示,通过reducer函数,我们传入对应的type就可以更新对应的state内容。
dispatch
上一步代码中,每次修改state时,都需要写setValue(reducer(appState,xxx)); 这一段,那么可以将这段代码封装成名为dispatch的函数
const dispatch = (action)=>{
setValue(reducer(appState,action))
}
function changeAge(e) {
const val = e.target.value;
dispatch({type:'changeAge',payload:{age:val}})
}
由于dispatch需要使用serValue ,而react规定setState 函数必须要在函数组件中定义,但是又不能每个组件都定义一个这样的方法。 可以利用高阶组件包装一下
const createWrapper = (Component) => {
return (props) => {
const { appState, setValue } = useContext(appContext);
const dispatch = (action) => {
setValue(reducer(appState, action));
};
return <Component dispatch={dispatch} state={appState} {...props}/>;
};
};
const 张三Wrapper = createWrapper(张三);
const App = () => {
const [appState, setValue] = useState({
name: "张三",
age: 18,
});
const contextValue = { appState, setValue };
return (
<appContext.Provider value={contextValue}>
<div className="container">
<div className="box">
<张三Wrapper />
</div>
<div className="box">
<李四 />
</div>
<div className="box">
<王五 />
</div>
</div>
</appContext.Provider>
);
};
export default App;
效果 
至此,一个简单的reducer和dispatch就完成。
总结
我们通过useConnext建立的上下文联系,在上文中定义了全局state,之后下传至每一个组件,通过reducer规范了构建全局新state的过程,又通过dispatch简化了修改state值的行为。而reducer和dispatch的作用也恰是如此,只不过我们的比较简易实现。
但是! 以上代码还是存在问题的,后续会提出。 错误的地方欢迎指正
未完待续
|