基本用法
使用函数组件
基本用法
遍历数组
绑定事件
多用于处理异步加载数据未返回时显示loading
生命周期
React中生命周期存在于类组件中,函数组件是没有生命周期的;但是函数组件可以通过hooks来模拟生命周期的回调
类组件-生命周期
三大阶段:挂载 / 更新 / 销毁
5个常用钩子:componentDidMount componentDidUpdate componentWillUnmount + render shouldComponentUpdate
- render:固定执行,决定组件模板的渲染
- componentDidMount:操作DOM、绑定事件、发起网络请求
- shouldComponentUpdate:组件接收到新的 props 或者 state 会触发,默认返回true,允许更新;自定义改成false,则不更新,页面空白(多用于性能优化)
- componentDidUpdate:组件更新完成
- componentWillUnmount:解绑事件、清除定时器等
函数组件 -(使用 Hooks 来模拟生命周期)
如何模拟:
- render(默认执行)
- componentDidMount + componentDidUpdate + componentWillUnmount = useEffect()
useEffect(() => {
// 模拟componentDidMount:操作DOM、绑定事件、发起网络请求
.......
return () => {
// 模拟 componentWillUnmount:解绑事件、清除定时器等
};
}, [
// 模拟componentDidUpdate
// 第二个参数设置为空数组[],代表不需要监听,就能达到只在挂载mount时执行一次;
// 这就是“消除副作用”
// 如果不是空数组,而是[demo],则监听demo的更新update
]);
useEffect()
为什么在<React.strcitMode />组件里包裹的组件会执行两次useEffect()里面的函数
为了倒逼开发者尽可能使用纯函数(多次执行同一函数,都是一样的结果);减少错误的产生(例如在组件卸载前记得还原变量到初始值、清理资源、取消订阅等重要操作,减少可能的内存泄漏和其他问题)
原理:官网提到,它会先模拟组件加载又卸载,然后再进行第二次加载;所以看起来就是执行了2次
官网原话:没必要不让它执行2次,因为开发者更应该学会让组件正确的加载卸载
五大钩子
HOC HOC
- 高阶函数(Higher Order Function,HOF)
高度抽象、模块化的function,如js数组的 map、filter、reduce 或者 React / Vue的生命周期钩子函数
- 高阶组件(Higher Order Component,HOC)
高度复用的component
// 身份验证的HOC
function withAuth(Component) {
return function(props) {
if (isLoggedIn()) {
return <Component {...props} />;
} else {
return <LoginScreen />;
}
};
}
const AuthenticatedComponent = withAuth(MyComponent);
最常用的3个hook
useState() : 定义组件的状态,如const [demo,setDemo] = useState(null);
useRef() : 响应式数据(和Vue3的ref()差不多)
useEffect() :只在页面初始化执行一次函数(副作用函数)
useState()
- 操作字符串
- 操作对象
- 操作数组
props的使用
父向子 - 简单通信
- 祖孙通信
- (预定义在children里面)
- 设定默认值
子向父
useReducer(升级版的useState)
多组件传值:createContext() useContext() 共享上下文
useMemo
类似于vue的watch+computed:监听变化+复杂计算+缓存数据
useCallback
类似于专门缓存【函数】版的useMemo
useEffect和useLayoutEffect的区别
【执行时机的不同】
useEffect属于异步,在浏览器渲染完成后执行
useLayoutEffect属于同步,在浏览器渲染前执行,可以避免页面的闪烁
React.strictMode
在开发模式下检查、暴露潜在问题,不会影响到生产模式
<Suspense />
异步组件
可在等待数据返回时显示Loading…
一般搭配React.lazy()
异步加载组件
import React, { Suspense } from 'react';
const LazyAaa = React.lazy(() => import('./Aaa'));
export default function App() {
return <div>
<Suspense fallback={'loading...'}>
<LazyAaa></LazyAaa>
</Suspense>
</div>
}
<ErrorBoundary />
错误边界
Hook的限制
-
自定义hook时尽量以use开头:约定俗成的,方便辨别
-
顶层作用域:指的是函数组件的直接内部,也就是在函数组件的花括号 {} 内部声明的区域。这意味着钩子应该在函数组件的开始部分被调用,而不是在内部嵌套的区域或者条件语句中。
function MyComponent() { // 顶层作用域 const [count, setCount] = useState(0); useEffect(() => { // 顶层作用域 // ... }, [count]); // 顶层作用域 if (count > 0) { // 不是顶层作用域 // 这里不能调用钩子 } // 顶层作用域 return <div>{count}</div>; }
-
循环、嵌套函数、条件语句中不能调用:这是因为 React 需要在渲染时能够正确地追踪和管理组件的状态变化,如果钩子被调用的位置在循环、嵌套函数或条件语句中,React 将无法准确地确定钩子何时被调用,从而可能导致不可预测的行为或错误。
function MyComponent() { // 顶层作用域 for (let i = 0; i < 5; i++) { // 不是顶层作用域 // 这里不能调用钩子 } // 顶层作用域 function helperFunction() { // 不是顶层作用域 // 这里不能调用钩子 } // 顶层作用域 if (condition) { // 不是顶层作用域 // 这里不能调用钩子 } // 顶层作用域 return <div>{/* ... */}</div>; }
通过遵守这个限制,可以确保 React 能够正确地追踪组件的状态变化,从而避免出现潜在的问题和错误。
React 18 更新
在 React 中,在父组件A 如何获取子组件 B (类组件和函数组件) 中的数据
- 类组件
- 使用
ref
- 使用
props
- 函数组件
- 使用
useRef
- 通过
props