React 部分常用API记录
本文档用于记录React内置的部分特定场景下的常用API,包括使用场景以及使用例子。
createPortal
Section titled “createPortal”React Portal是React提供的一种将子节点渲染到父组件DOM层次结构之外的DOM节点中的方法,同时保持其在React组件树中的位置。
使用场景:
-
模态框(Modals):模态框通常需要覆盖整个页面,并且不受父容器样式(如
overflow: hidden或z-index)的影响。使用Portal可以将模态框渲染到body的直接子元素,避免被父组件剪裁。 -
工具提示(Tooltips):当工具提示需要突破父容器的溢出隐藏或定位上下文时,可以使用Portal将其渲染到更高层级的DOM节点上。
-
弹出菜单(Popup Menus):类似工具提示,弹出菜单可能需要避免被父容器的样式所影响,确保正确显示。
-
通知(Notifications):全局的通知消息通常需要显示在页面的顶部,不受其他组件布局的影响。
-
悬停卡(Hover Cards):当鼠标悬停在某个元素上时显示的信息卡,有时需要突破父元素的布局限制。
-
对话框(Dialogs):与模态框类似,对话框通常需要覆盖整个页面,并且应该位于其他内容之上。
-
加载遮罩(Loading Overlays):全屏的加载指示器,需要覆盖整个页面或某个区域,并且位于所有内容之上。
使用例子(弹出框):
const Modal = ({ children, isOpen, onClose }) => { const [modalRoot] = useState(() => document.getElementById('modal-root')); const [el] = useState(() => document.createElement('div'));
useEffect(() => { if (isOpen) { modalRoot.appendChild(el); document.body.style.overflow = 'hidden'; // 防止背景滚动
return () => { modalRoot.removeChild(el); document.body.style.overflow = 'unset'; }; } }, [isOpen, el, modalRoot]);
if (!isOpen) return null; return ReactDOM.createPortal( <div className="modal-backdrop" onClick={onClose}> <div className="modal" onClick={e => e.stopPropagation()}> {children} </div> </div>, el);};React.lazy + Suspense
Section titled “React.lazy + Suspense”React.lazy用于懒加载组件,传入一个load函数,返回一个懒加载组件:
import { lazy } from 'react';
const MarkdownPreview = lazy(() => import('./MarkdownPreview.js'));使用Suspense组件可以在懒加载的过程中插入一些中间态UI,用法如下:
<Suspense fallback={<Loading />}> <MarkdownPreview /></Suspense>其中fallback属性传入的就是中间态的UI(如Loading组件)。
useTransition
Section titled “useTransition”useTransition是React 18引入的一个并发特性(Concurrent Feature),它允许你将一个状态更新标记为非阻塞的、可中断的过渡更新(Transition),从而让高优先级的更新(如用户输入、点击)能够打断它,保持用户界面的流畅和响应。
在没有useTransition之前,所有的状态更新都是“紧急”的。当一个耗时的状态更新(如根据用户输入过滤一个超长列表)发生时,它会阻塞线程,导致用户输入无法立即得到响应,输入框会感觉“卡顿”。
经典场景:一个搜索输入框 + 一个搜索结果列表:
用户在输入框中快速输入 “hello”。每次按键都会触发一个状态更新setInputValue,并随之触发一个昂贵的计算来过滤列表setSearchResults。由于setSearchResults计算量很大,它会阻塞UI线程。导致用户输入的下一个字符无法立即渲染,输入框看起来停止了响应,直到过滤计算完成。
使用useTransition后,你可以将过滤列表的更新标记为一个“过渡更新”。这样,setInputValue(紧急更新)会立即执行,让输入框内容变化;而setSearchResults(过渡更新)可以被中断或延迟,不会阻塞输入框的渲染。用户体验会变得非常流畅。
代码示例如下:
// 假设有两个状态:输入值 和 搜索结果const [inputValue, setInputValue] = useState('');const [searchResults, setSearchResults] = useState([]);const [isPending, startTransition] = useTransition();
const handleInputChange = (e) => { const value = e.target.value;
// 1. 紧急更新:立即更新输入框的值 setInputValue(value);
// 2. 过渡更新:将昂贵的列表更新包裹起来 startTransition(() => { // 在这个回调函数内部的所有状态更新都会被标记为过渡更新 const filteredResults = hugeList.filter(item => item.name.includes(value) ); setSearchResults(filteredResults); });};