React:用于构建用户界面的JavaScript库。
React哲学(Thinking In React)
React是用JavaScript构建快速响应的大型Web应用程序的首选方式之一。
影响Web性能的两大主要原因:(快速响应的瓶颈)
解决方法:
- 等待资源加载
- React.Lazy(动态加载)
- React.Suspense
- ErrorBoundary(资源加载失败提示)
- 浏览器线程执行
- 异步更新
- 时间切片
- React Fiber
import React, { useState, Suspense } from 'react'; // 引入React相关组件
import { Tabs } from 'antd'; // 引入Ant Design中的Tabs组件
// 定义组件
const MyTabs = ({ routes }) => {
const [activeKey, setActiveKey] = useState('1'); // 用useState定义当前激活的Tab key
// 组件渲染方法
const renderTabs = () => {
return routes.map((item) => {
const Component = React.lazy(() => import(`./${item.key}`)); // 使用React.lazy动态加载Tab内容
// 定义Tab内容渲染方法
const RenderComponent = (
<Suspense fallback={"资源加载中..."}>
<Component />
</Suspense>
);
// 返回一个TabPane组件
return (
<Tabs.TabPane key={item.key} title={item.name}>
{RenderComponent}
</Tabs.TabPane>
);
});
};
// 返回最终的Tabs组件
return (
<Tabs activeTab={activeKey} onChange={setActiveKey}>
{renderTabs()}
</Tabs>
);
};
// 导出组件
export default MyTabs;
更新流程
-
Scheduler(调度器)
- 维护时间切片(类似requestldleCallback)
- 与浏览器任务调度
- 优先级调度
-
Reconciler(协调器)
- 将JSX(React中的特殊语法)转化为Fiber
- Fiber树对比(双缓存)
- 确定本次更新的Fiber
-
Renderer(渲染器)
- 渲染器用于管理一棵React树,使其根据底层平台进行不同的调用。
优缺点:
优点:
- 快速响应:Fiber
- 组件化:复用性强
- 声明式编程
- 跨平台:只需修改渲染器
缺点:
- 大型引用需要配套学习 状态管理、路由设备
- 不适合小型应用,需要用Babel处理
React基础
Web 应用
- 打包配置:JSX -> babel -> JS加载优化和错误降级。
- React Router向应用中快速地添加视图和数据流,保持页面与URL间的同步。
- 可复用UI -> 组件 -> 页面。可复用逻辑抽离成hook。
- 多页面多组件共享信息redux & context
组件
- 通过定义state操作视图Mount时获取数据更新stateRef保存与视图无直接关系的值unMount前清空Ref
- props父子组件通信context & redux组件信息共享
- 数据决定视图通过Ref获取到DOM
- 函数使用useCallback值或者计算使用useMemo组件包裹memo
函数式组件的优点:
- 代码量骤减,组件干净清爽
- 没有复杂的生命周期
- 支持自定义hook,逻辑复用方便
Hook规则 & 原理
组件和Hook的关系
- 我们将UI拆成多个独立单元,这些单元组合可以构成多种视图展示,这些独立单元就是组件。组件相当于原子。
- hook贴近组件内部运行的各种概念逻辑,effect、state、context等。hooks更贴切于电子。
只能在 React 函数中调用Hook
-
在React函数组件中 或自定义Hook中调用
-
自定义Hook必须以use开头
-
Hook中的state是完全隔离的
Hook过期闭包问题
过期闭包指的是当一个变量在创建闭包时被捕获,并且该变量在后续的执行过程中发生了改变,而闭包中仍然保存着旧值的情况。
因为因为 Hook 可以在函数组件中捕获和更新组件状态,并且每次渲染时都会重新执行,确保状态的正确性。所以使用Hook解决过期闭包问题。
如程序:
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return <button onClick={handleClick}>点击 {count} 次</button>;
}
由于 useState Hook 在每次渲染时都会重新执行,因此 count 变量和 setCount 函数的闭包是实时更新的,避免了过期闭包问题的出现。
React常用API及其作用
类组件基类 React.Component
React.Component是 React 类组件的基类。- 类组件继承
React.Component后,可以通过实现render方法来返回要渲染的 React 元素。
浅层对比 React.PureComponent
React.PureComponent继承自React.Component,并重写了shouldComponentUpdate()方法。React.PureComponent内置了浅层对比(shallow compare) props 和 state 进行性能优化。- 适用于组件仅依赖于 props 和 state 的情况。
高阶组件 React.memo
React.memo是一个高阶组件,用于只比较props变更的情况下避免不必要的渲染。- 当前组件的
props不变时,React.memo可以使用上一次渲染结果缓存,从而提高性能。
创建 React 元素 React.createElement
React.createElement是创建并返回 React 元素的函数,可以用于在不使用 JSX 的情况下构建 React 应用。- 函数的第一个参数是标签名或组件类型,第二个参数是 props,第三个参数及之后的参数是子元素。
克隆 React 元素 React.cloneElement
React.cloneElement是用于克隆并返回包含新 props 的 React 元素的函数。- 可以通过这个函数为新元素添加额外
props或者覆盖原有props。
遍历操作 React.Children
React.Children.map用于遍历 React 子元素并返回一个新的子元素数组,可以在遍历过程中为子元素添加或修改props。React.Children.forEach用于遍历 React 子元素,不能返回新的子元素数组。React.Children.count用于获取子元素数量。React.Children.only用于判断是否只有一个子元素。
创建 ref React.createRef
React.createRef用于创建一个 ref,并附加到具体元素上,在 class 组件中可以使用该 ref 获取 dom 结构。
转发 ref React.forwardRef
React.forwardRef可以让组件转发 ref,使父组件可以获取子组件的 dom 元素或执行子组件的方法。- 可与
useImperativeHandle配合使用。
动态加载组件 React.lazy
React.lazy可以实现组件的动态加载和构建,提高应用性能。- 只能在函数组件中使用,不支持 SSR 和服务端渲染。
优雅降级 React.Suspense
React.Suspense是一个组件,在资源未准备好时可以优雅地降级。- 可以用于等待代码分割、组件懒加载、异步请求等场景。
React常用Hooks及其使用
React Hooks 是 React 16.8 引入的一项功能,可以让函数组件拥有类似于 class 组件的功能。以下是 React Hooks 的常用函数:
useState
useState返回一个数组[state, setState],其中state表示当前状态的值,setState是一个函数,用于更新state的值。
useEffect
useEffect用于在函数组件中执行副作用操作,比如网络请求、订阅事件等。- 可以在挂载后、依赖变化时、组件卸载前等场景下执行操作。
- 接收两个参数:第一个参数是一个函数,表示要执行的操作;第二个参数是一个数组,用于指定影响该操作的变量,若该数组为空,则表示该操作仅在挂载和卸载时执行。
useContext
useContext用于接收最近的上层context对象,并返回其值。- 一般与
createContext一起使用,可以让子组件获取到父组件传递下来的数据。
useRef
useRef返回一个可变的ref对象,在组件生命周期内持续存在。- 可以用于保存任意可变值,也可以和其他 DOM API 一起使用获取 DOM 元素或者保存一些组件内的状态。
useMemo
useMemo接收两个参数:第一个参数是计算函数,第二个参数是依赖数组。- 只有在依赖项变化时才调用计算函数,并返回计算值。
- 可以用于优化计算量较大的操作。
useCallback
useCallback(fn, deps)相当于useMemo(() => fn, deps),一般返回的是一个新函数。- 可以用于避免子组件不必要地重新渲染。
useReducer
useReducer是useState的更丰富替代方案。- 返回
[state, dispatch],其中state可以是复杂对象,dispatch可以更新这个复杂对象。
useImperativeHandle
useImperativeHandle可以让组件向父组件暴露方法。- 一般和
forwardRef一起使用。
useLayoutEffect
useLayoutEffect的执行时机是浏览器把内容真正渲染到界面之前,和componentDidMount等价。- 和
useEffect的执行时机不同,useEffect的执行时机是在浏览器完成渲染之后。
具体场景案例
-
对一个网页划分组件
-
_Layout
-
_Page
-
_Component
-
-
组件间通信案例
-
组件间共享信息
-
组件性能优化
-
组件挂载位置
-
逻辑复用
总结
React是一个用于构建用户界面的JavaScript库,它通过组件化、声明式编程和虚拟DOM等特性,提供了高效的UI渲染和管理方式。React Hooks的出现使得函数组件具备类似于class组件的功能,包含了useState、useEffect、useContext、useRef、useMemo、useCallback等常用API,可以帮助开发者快速高效地实现各种功能,同时也需要注意优化组件的性能。