初衷
发现网上很少有用 TypeScript 写的 React hooks 教程,大部分是 JavaScript 写的,还是老旧的类组件的写法,函数组件都推出多少年了,建议新手直接上 hooks 函数写法,另外很多教程解释的也不太清楚,看起来云里雾里,官方文档也一样
对于从其他端(移动端、后端)转到前端的开发者,一开始可能比较难理解 React 的编程思想(不要问我怎么知道的)
于是写了这些面向非前端开发者的 React Hooks 系列教程,希望能帮助大家少走弯路
创建项目
这里使用 Vite 创建 React + TypeScript 的项目,当然你也可以用 React 官方的 create-react-app 来创建
npm init vite@latest
运行上面命令,输入项目名,选择 react 再选择 react-ts 如下图
然后进入工程目录,先执行如下命令,安装 npm 依赖包:
npm install
再执行如下命令,运行项目:
npm run dev
在浏览器打开 http://localhost:3000/ 就能看到项目了
useState 示例
修改 App.tsx 文件,把整个 App 函数替换为下面的代码
type TProps = {
id?: number;
name?: string;
};
const App: React.FC<TProps> = (props) => {
const [state, setState] = React.useState<number>(0);
console.log("app render");
return (
<div
onClick={() => {
setState((state) => state + 1);
console.log("state:", state);
}}
>
state: {state}
</div>
);
};
先介绍下上面代码中涉及 React 的用法
第 6 行
React.FC<TProps>
FC 是 FunctionComponent 的缩写,用来定义函数组件,后面尖括号里面 TProps 为类型,类型用 type 或 interface 定义,和 Java 泛型定义差不多
第 7 行
const [state, setState] = useState<number>(0);
useState 用来定义由 React 管理的变量,返回一个数组,数组内第一个用于获取值,第二个用于更新值,相当于 Java 里的 get set 函数,后面括号内是初始值,尖括号用于定义类型可不加,若没有声明类型会从初始值自动推断
setState 有两种更新值的方式:
- 直接替换:
setState(1)
- 在上一次基础上更新:
setState((state) => state + 1)
运行结果如下,我们点击一下页面的值就加 1,符合预期
看日志可以发现 state 值每次改变后都会打印“app render”,说明触发了重新渲染,代码重新执行了,虽然第 7 行代码重新执行了,但是 state 却没有重新设置为 0,如果这里是 let 声明的,那么值肯定就被重置了,感兴趣的小伙伴可以自己试下
另外有细心的小伙伴可能发现,日志打印出来的值总是比页面上显示的值少 1,这是因为 setState 不是立即执行的,React 会异步统一处理,提高效率
下面看看用 let 的方式,替换为下面的代码
type TProps = {
id?: number;
name?: string;
};
let num = 0;
const App: React.FC<TProps> = (props) => {
console.log("app render");
return (
<div
onClick={() => {
num = num + 1;
console.log("num:", num);
}}
>
num: {num}
</div>
);
};
你会发现无论怎么点击,页面上值没有更新,虽然控制台日志显示值更新了
与前面 useState 运行日志对比可以发现,state 值每次改变后都会打印“app render”,而 let 这边只有第一次进入页面打印了“app render”,说明 let 不能触发页面重新渲染,所以页面上的值也不会变
另外全局 let 还有一个问题,当我们切换到另一个页面时,let 声明的全局变量还是存在的,不会随着页面销毁,我们得手动清理它,这样就不方便了
总结,useState 的作用:
- 在值变化时触发页面重新渲染
- 在重新渲染时保存值不被重置
- 在组件销毁或页面切换时自动清理值