React教程,函数组件状态管理useState/useReducer总结
发布于 作者:苏南大叔 来源:程序如此灵动~ 我们相信:世界是美好的,你是我也是。平行空间的世界里面,不同版本的生活也在继续...
在本文中,苏南大叔对React
中useState()
钩子做个简单的总结,总结的目的主要是引出useState()
存在的问题,为后续文章提出的可能的解决方案,做伏笔铺垫。
苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码编程经验总结。本文测试环境:nodejs@20.18.0
,create-react-app@5.0.1
,react@19.0.0
。useState()
是目前的React
项目中,最最常用的钩子。
前文回顾
在传统类组件中,可以使用state
,参考文章:
在函数组件里面,通过useState()
使用state
的方法。参考文章:
React
官方出品的useReducer()
钩子,对useState()
钩子的一个升级使用方式,参考文章:
useState()简单使用
import React, { useState } from "react";
const App = () => {
const [count, setCount] = useState(0);
return (
<>
{count}
<button onClick={() => setCount(count + 1)}>+1</button>
<button onClick={() => setCount( state => state + 2)}>+2</button>
<button onClick={() => setCount((state) => state + 3)}>[推荐方式]+3</button>
</>
);
};
export default App;
这里推荐的写法就是:
() => setCount((state) => state)}
useState()进阶使用
这里主要是利用...
运算,修改稍微复杂的对象。代码参考:
import React, { useState } from "react";
const App = () => {
let [info, setInfo] = useState({
name: "苏南大叔",
city: "beijing",
});
return (
<>
{info.name},{info.city}
<button
onClick={() => {
info.city = "yanjiao"; // 无效不会改变的
setInfo(info); // 这个也无效
}}
>
修改city,但是无效
</button>
<button onClick={() => setInfo({ ...info, city: "tangshan" })}>
对象改变,但不推荐
</button>
<button
onClick={() => {
setInfo((info) => {
return { ...info, name: "sunan大叔" };
});
}}
>
推荐写法
</button>
<button
onClick={() => {
setInfo({
name: "苏南大叔",
city: "beijing",
});
}}
>
重置
</button>
</>
);
};
export default App;
useState()最经典案例
最经典的useState()
的例子,setInterval()
+useState()
+稍复杂对象。
import React, { useState, useEffect, useRef } from "react";
function Timer() {
const [seconds, setSeconds] = useState({ s: 0 });
const intervalRef = useRef(null);
const a = () => {
setSeconds((seconds) => {
return {
...seconds,
...{ s: seconds.s + 1 },
};
});
};
useEffect(() => {
intervalRef.current = setInterval(() => {
a();
}, 1000);
return () => clearInterval(intervalRef.current);
}, []); // 组件挂载时执行
return <div>Seconds: {seconds.s}</div>;
}
export default Timer;
这个例子就是对上面两个例子的结论肯定。尽量使用setState((state)=>{})
,内部使用...
对状态进行展开。如果不遵守这个规则的话,这个setInterval()
的例子就无法正常运行。
useReducer()改写
这里使用React
官方的useReact()
的升级版useReducer()
方案,再次改写上面的特殊例子。
import React, { useReducer, useEffect, useRef } from "react";
const reducer = (state, action) => {
switch (action.type) {
case "name":
return { ...state, ...{ name: action?.name } };
case "gold":
return { ...state, ...{ gold: state?.gold + 1 } };
case "reset":
return { ...action?.info };
default:
throw new Error("未识别操作");
}
};
function App() {
const [info, dispatch] = useReducer(reducer, {
name: "Uncle sunan",
gold: 10000,
});
const intervalRef = useRef(null);
useEffect(() => {
intervalRef.current = setInterval(() => {
dispatch({ type: "gold" });
}, 1000);
return () => clearInterval(intervalRef.current);
}, []); // 组件挂载时执行
return (
<>
{info.name},{info.gold}
<button
onClick={() => {
dispatch({ type: "name", name: "苏南大叔" });
}}
>
name
</button>
<button
onClick={() => {
dispatch({
type: "reset",
info: { name: "Uncle sunan", gold: 10000 },
});
}}
>
reset
</button>
</>
);
}
export default App;
这个例子的成功运行,表明:因为useReducer
是强制使用state
变量的。所以,遵守规则的前提下(也就是说在reducer
内部使用state
),setInterval()
和useReducer()
是不会产生冲突的。变量是可以正常更新的。
结语
更多react
例子,请参考苏南大叔的博客文章:
如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。