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,可以帮助开发者快速高效地实现各种功能,同时也需要注意优化组件的性能。