React 是一个用于构建用户界面的 JavaScript 库。它以声明式的方式让开发者可以轻松构建复杂且交互性强的 UI。要真正驾驭 React,深入理解其核心 API 至关重要。这些 API 是构建组件、管理状态、处理副作用、优化性能以及与其他系统交互的基础。本文将对 React 的核心 API 进行深度解读,涵盖从组件定义到高级优化等各个方面。

核心思想:React 核心 API 围绕组件化、声明式UI、单向数据流和性能优化展开,通过 Hooks 极大地简化了函数组件的状态管理和副作用处理,使复杂逻辑更易组织和复用。


一、React 的核心模块与入口

React 库被拆分为两个主要模块:reactreact-dom

  • react: 包含构建组件和定义其行为所需的核心 API(如 Component, useState, useEffect, createContext 等)。
  • react-dom: 提供与 DOM 交互的特定方法(如 render, createRoot 等),用于将 React 组件渲染到浏览器环境。

react-dom 主要 API

1. createRoot(container) (React 18+)

用途: 用于在客户端首次渲染 React 应用,是 React 18 引入的新的根 API,支持并发特性如 Concurrent Mode 和 Suspense。

参数:

  • container: 一个 DOM 元素,React 将在该元素内部渲染您的组件。

返回值: 一个根对象 (Root)。

示例:

1
2
3
4
5
6
7
8
9
10
import React from 'react';
import { createRoot } from 'react-dom/client'; // 注意这里是从 'react-dom/client' 导入
import App from './App';

const container = document.getElementById('root');
const root = createRoot(container); // 创建根
root.render(<App />); // 渲染应用

// 或者在其他地方更新或卸载
// root.unmount(); // 卸载组件树

2. render(element, container, [callback]) (React 17 及以下)

用途: 将一个 React 元素渲染到提供了的 container DOM 节点中,并返回对组件实例的引用(对于类组件)。

参数:

  • element: 要渲染的 React 元素(通常是 JSX)。
  • container: DOM 元素,React 将在其内部渲染内容。
  • callback (可选): 在组件渲染或更新后执行的回调函数。

示例:

1
2
3
4
5
6
7
8
9
10
import React from 'react';
import ReactDOM from 'react-dom'; // 注意这里是从 'react-dom' 导入
import App from './App';

ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);

3. unmountComponentAtNode(container) (React 17 及以下)

用途: 从 DOM 中移除已挂载的 React 组件,清理其事件处理器和状态。

示例:

1
ReactDOM.unmountComponentAtNode(document.getElementById('root'));

二、组件定义 API

React 主要提供两种组件定义方式:函数组件 (Function Components) 和类组件 (Class Components)。随着 Hooks 的引入,函数组件已成为主流。

1. 函数组件 (Function Components)

定义: 普通的 JavaScript 函数,接收 props 对象作为参数,并返回一个 React 元素(通常是 JSX)。

特点:

  • 无状态 (在 Hooks 出现之前)。
  • 更简洁、易于测试。
  • 配合 Hooks 使用,可以拥有状态和生命周期等功能。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import React from 'react';

// 简单函数组件
function Greeting(props) {
return <h1>Hello, {props.name}!</h1>;
}

// 箭头函数形式 (常见)
const Farewell = (props) => {
return <p>Goodbye, {props.name}.</p>;
};

// 带解构的函数组件
const Profile = ({ name, age }) => {
return (
<div>
<p>Name: {name}</p>
<p>Age: {age}</p>
</div>
);
};

2. 类组件 (Class Components)

定义: ES6 类,继承自 React.Component,且必须实现 render() 方法。

特点:

  • 拥有自身的状态 (state)。
  • 可以通过生命周期方法 (componentDidMount, componentDidUpdate, componentWillUnmount 等) 响应组件的生命周期事件。
  • 在 React 16.8 (Hooks 引入) 之后,不建议在新项目中使用,但仍需了解其概念。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import React, { Component } from 'react'; // 导入 Component

class Timer extends Component {
constructor(props) {
super(props);
this.state = { count: 0 }; // 初始化 state
}

componentDidMount() { // 组件挂载后执行
this.timerID = setInterval(() => this.tick(), 1000);
}

componentWillUnmount() { // 组件卸载前执行
clearInterval(this.timerID);
}

tick() {
this.setState(prevState => ({ // 使用函数形式更新 state
count: prevState.count + 1
}));
}

render() { // 必须实现 render 方法
return <p>Count: {this.state.count}</p>;
}
}

三、React Hooks API (React 16.8+)

Hooks 是函数组件的核心。它们允许你在不编写 class 的情况下使用 state 和其他 React 特性。

1. useState

用途: 为函数组件添加状态。

语法: const [state, setState] = useState(initialState);

参数:

  • initialState: 状态的初始值。可以是任意类型,也可以是一个函数(该函数只会在首次渲染时执行,用于惰性初始化)。

返回值: 一个数组,包含:

  • 当前状态值。
  • 一个用于更新状态的函数。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// Counter.jsx
import React, { useState } from 'react';

function Counter() {
const [count, setCount] = useState(0); // number 状态
const [message, setMessage] = useState(''); // string 状态
const [user, setUser] = useState({ name: 'Guest', age: 0 }); // object 状态

const increment = () => {
setCount(prevCount => prevCount + 1); // 推荐使用函数式更新,避免闭包问题
};

const updateUserName = (newName) => {
// 对于对象状态,setState 不会合并,需要手动合并
setUser(prevUser => ({ ...prevUser, name: newName }));
};

return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
<p>User Name: {user.name}</p>
<button onClick={() => updateUserName('Alice')}>Set Alice</button>
<input type="text" value={message} onChange={(e) => setMessage(e.target.value)} />
<p>Message: {message}</p>
</div>
);
}

2. useEffect

用途: 在函数组件中执行副作用操作(数据获取、订阅事件、手动修改 DOM、清理等)。它替代了类组件的 componentDidMount, componentDidUpdate, componentWillUnmount

语法: useEffect(setup, [dependencies]);

参数:

  • setup: 包含副作用逻辑的函数。此函数可以返回一个清理函数(可选)。
  • dependencies (可选数组): 一个依赖项数组。
    • 如果省略,useEffect 每次渲染后都会执行。
    • 如果为空数组 []useEffect 只会在组件挂载时执行一次,并在组件卸载时执行清理函数(类似于 componentDidMountcomponentWillUnmount)。
    • 如果包含依赖项,useEffect 会在依赖项发生变化时重新执行。

返回值: 无。

清理函数: useEffect 返回的函数会在下次 useEffect 执行前或组件卸载时执行,用于清理上次作用(如取消订阅、清除定时器)。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import React, { useState, useEffect } from 'react';

function DataFetcher({ userId }) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);

useEffect(() => {
console.log(`Fetching data for userId: ${userId}`);
setLoading(true);
setError(null);
setData(null); // 清空旧数据

const abortController = new AbortController(); // 用于取消请求
const signal = abortController.signal;

fetch(`https://jsonplaceholder.typicode.com/users/${userId}`, { signal })
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(json => {
setData(json);
})
.catch(err => {
if (err.name === 'AbortError') { // 防止在组件卸载后更新状态
console.log('Fetch aborted');
} else {
setError(err);
}
})
.finally(() => {
setLoading(false);
});

// 清理函数
return () => {
console.log(`Cleaning up for userId: ${userId}`);
abortController.abort(); // 取消未完成的请求
};
}, [userId]); // 依赖项数组,当 userId 变化时重新执行 effect

if (loading) return <div>Loading user data...</div>;
if (error) return <div>Error: {error.message}</div>;
if (!data) return <div>No data found.</div>;

return (
<div>
<h2>User Profile</h2>
<p>Name: {data.name}</p>
<p>Email: {data.email}</p>
</div>
);
}

// 在 App 中使用
// <DataFetcher userId={1} />
// <DataFetcher userId={2} /> // 切换 userId 会重新触发 effect

3. useContext

用途: 订阅 React Context 的值。这使得组件可以直接访问组件树中更高层组件提供的 Context 值,避免了 props 层层传递。

语法: const value = useContext(MyContext);

参数:

  • MyContext: 由 React.createContext() 创建的 Context 对象。

返回值: Context 对象的当前值。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import React, { createContext, useContext, useState } from 'react';

// 1. 创建 Context,并提供默认值
const ThemeContext = createContext('light');

// 2. 提供者组件
function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
const toggleTheme = () => setTheme(t => (t === 'light' ? 'dark' : 'light'));

const contextValue = { theme, toggleTheme }; // 包装成对象

return (
<ThemeContext.Provider value={contextValue}>
{children}
</ThemeContext.Provider>
);
}

// 3. 消费者组件
function ThemedButton() {
const { theme, toggleTheme } = useContext(ThemeContext); // 从 Context 中获取值
return (
<button className={theme} onClick={toggleTheme}>
Current theme: {theme}
</button>
);
}

// 4. 应用中使用
function App() {
return (
<ThemeProvider>
<div>
<h1>My App</h1>
<ThemedButton />
<p>Some other content...</p>
</div>
</ThemeProvider>
);
}

4. useRef

用途: 创建一个可变的 ref 对象,其 .current 属性可以在组件的整个生命周期中保存可变值,而不会导致重新渲染。最常见的用途是访问 DOM 元素。

语法: const refContainer = useRef(initialValue);

参数:

  • initialValue: ref 对象 .current 属性的初始值。

返回值: 一个具有 current 属性的普通 JavaScript 对象。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import React, { useRef, useEffect } from 'react';

function FocusInput() {
const inputRef = useRef(null); // 初始值为 null

useEffect(() => {
// 确保 inputRef.current 存在(组件已挂载)
if (inputRef.current) {
inputRef.current.focus(); // 自动聚焦 input 元素
}
}, []); // 空数组表示只在组件挂载时执行一次

const handleClick = () => {
if (inputRef.current) {
alert(`Input value: ${inputRef.current.value}`);
}
};

return (
<div>
<input type="text" ref={inputRef} /> {/* 将 ref 绑定到 DOM 元素 */}
<button onClick={handleClick}>Show Input Value</button>
</div>
);
}

5. useReducer

用途: useState 的替代方案,用于管理更复杂的 state 逻辑,例如涉及多个子值的 state,或者下一个 state 依赖于前一个 state。它与 Redux 的 reducer 概念相似。

语法: const [state, dispatch] = useReducer(reducer, initialArg, init);

参数:

  • reducer(state, action): 一个纯函数,根据 stateaction 计算新的 state
  • initialArg: 初始状态。
  • init (可选): 一个惰性初始化函数,如果提供,则 initialArg 将作为其参数,其返回值作为初始状态。

返回值: 一个数组,包含:

  • 当前状态值。
  • 一个 dispatch 函数,用于派发 action 来更新 state。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import React, { useReducer } from 'react';

// 1. 定义 reducer 函数
const initialState = { count: 0 };

function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
case 'reset':
return initialState; // 重置到初始状态
case 'set':
return { count: action.payload };
default:
throw new Error();
}
}

function CounterWithReducer() {
const [state, dispatch] = useReducer(reducer, initialState);

return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: 'increment' })}>Increment</button>
<button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button>
<button onClick={() => dispatch({ type: 'reset' })}>Reset</button>
<button onClick={() => dispatch({ type: 'set', payload: 100 })}>Set to 100</button>
</div>
);
}

6. useCallback

用途: 记住(memoize)一个回调函数。当把回调函数作为 prop 传递给优化过的子组件时,或者作为 useEffect 的依赖项时,useCallback 可以避免不必要的重新创建函数实例,从而防止子组件不必要的重新渲染。

语法: const memoizedCallback = useCallback(callback, [dependencies]);

参数:

  • callback: 要记住的函数。
  • dependencies (数组): 依赖项数组。只有当依赖项发生变化时,callback 才会重新创建。

返回值: 记忆化的函数。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import React, { useState, useCallback, memo } from 'react';

// 子组件,使用 React.memo 进行性能优化
const ChildComponent = memo(({ onClick, value }) => {
console.log('ChildComponent rendered');
return (
<button onClick={onClick}>
Click me ({value})
</button>
);
});

function ParentComponent() {
const [count, setCount] = useState(0);
const [name, setName] = useState('Alice');

// 每次 ParentComponent 渲染,handleClick 都会重新创建,导致 ChildComponent 重新渲染
// const handleClick = () => setCount(prevCount => prevCount + 1);

// 使用 useCallback 记住 handleClick。只有当 count 变化时,才会重新创建 handleClick。
const handleClick = useCallback(() => {
setCount(prevCount => prevCount + 1);
}, []); // 依赖项为空,表示函数只在首次渲染时创建一次

// 如果 handleClick 依赖 count,则需要将其加入依赖数组
// const handleClick = useCallback(() => {
// setCount(count + 1); // 这里的 count 依赖 state
// }, [count]); // 当 count 变化时,重新创建 handleClick

return (
<div>
<p>Parent Count: {count}</p>
<ChildComponent onClick={handleClick} value={count} />
<input type="text" value={name} onChange={(e) => setName(e.target.value)} />
<p>Parent Name: {name}</p>
</div>
);
}

7. useMemo

用途: 记住(memoize)一个计算结果。它会在依赖项不变的情况下,避免重复执行昂贵的计算。

语法: const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

参数:

  • computeExpensiveValue: 一个在渲染期间执行的函数,返回要记住的值。
  • dependencies (数组): 依赖项数组。只有当依赖项发生变化时,函数才会重新执行。

返回值: 记忆化的计算结果。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import React, { useState, useMemo } from 'react';

function calculateFactorial(n) {
console.log(`Calculating factorial for ${n}...`);
if (n < 0) return -1;
if (n === 0) return 1;
let result = 1;
for (let i = 1; i <= n; i++) {
result *= i;
}
return result;
}

function FactorialCalculator() {
const [number, setNumber] = useState(1);
const [incrementor, setIncrementor] = useState(0);

// 每次 incrementor 变化时,calculateFactorial 都会重新执行
// const factorial = calculateFactorial(number);

// 使用 useMemo,只有当 name 变化时,才会重新计算阶乘
const factorial = useMemo(() => calculateFactorial(number), [number]);

return (
<div>
<p>Factorial of {number} is: {factorial}</p>
<button onClick={() => setNumber(number + 1)}>Increment Number ({number})</button>

<p>Incrementor: {incrementor}</p>
<button onClick={() => setIncrementor(incrementor + 1)}>Increment Incrementor ({incrementor})</button>
</div>
);
}

8. useImperativeHandle

用途: 允许在 useRef 配合 forwardRef 使用时,自定义暴露给父组件的实例值,从而限制父组件可以访问的子组件内部功能。

语法: useImperativeHandle(ref, createHandle, [dependencies]);

参数:

  • ref: 由 React.forwardRef 提供的 ref 对象。
  • createHandle: 一个函数,返回父组件将通过 ref.current 访问到的值。
  • dependencies (数组): 当依赖项变化时,createHandle 会重新执行。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import React, { useRef, useImperativeHandle, forwardRef } from 'react';

// 子组件 SmallInput 必须用 forwardRef 包裹
const SmallInput = forwardRef(({ label }, ref) => {
const inputEl = useRef(null);

// 使用 useImperativeHandle 自定义 ref.current 的值
useImperativeHandle(ref, () => ({
focusInput: () => { // 暴露一个 focusInput 方法给父组件
inputEl.current.focus();
},
clearInput: () => { // 暴露一个 clearInput 方法
inputEl.current.value = '';
},
getInputValue: () => inputEl.current.value // 暴露一个读取值的方法
}));

return (
<div>
<label>{label}: </label>
<input type="text" ref={inputEl} />
</div>
);
});

function ParentComponentWithInputHandle() {
const inputRef = useRef(null);

const handleFocus = () => {
if (inputRef.current) {
inputRef.current.focusInput(); // 调用子组件暴露的方法
}
};

const handleClear = () => {
if (inputRef.current) {
inputRef.current.clearInput();
}
};

const handleAlertValue = () => {
if (inputRef.current) {
alert(`Input value is: ${inputRef.current.getInputValue()}`);
}
};

return (
<div>
<SmallInput label="My text" ref={inputRef} />
<button onClick={handleFocus}>Focus Input</button>
<button onClick={handleClear}>Clear Input</button>
<button onClick={handleAlertValue}>Alert Value</button>
</div>
);
}

9. useLayoutEffect

用途: 与 useEffect 类似,但它在所有 DOM 变更后同步执行,浏览器在绘制前。适用于需要测量 DOM 布局(如滚动位置、元素尺寸)或执行与 DOM 视觉渲染紧密相关的副作用。

语法: useLayoutEffect(setup, [dependencies]);

特性:

  • 它的回调函数会在浏览器执行绘制之前执行,因此可以同步修改 DOM 布局。
  • 会阻塞浏览器的绘制,如果执行时间过长,可能导致性能问题。
  • 通常情况下,优先使用 useEffect,只有当需要同步操作 DOM 并且这会影响用户可见的布局时才使用 useLayoutEffect

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import React, { useState, useRef, useLayoutEffect } from 'react';

function Tooltip({ children, position }) {
const [tooltipStyle, setTooltipStyle] = useState({});
const tooltipRef = useRef(null);

useLayoutEffect(() => { // 同步测量,在浏览器绘制前调整位置
if (tooltipRef.current) {
const { width, height } = tooltipRef.current.getBoundingClientRect();
if (position === 'top') {
setTooltipStyle({ transform: `translateY(-${height + 10}px)` });
} else if (position === 'left') {
setTooltipStyle({ transform: `translateX(-${width + 10}px)` });
}
// ... 更多位置计算
}
}, [position]);

return (
<div style={{ position: 'relative', display: 'inline-block' }}>
{children}
<div ref={tooltipRef} style={{ ...tooltipStyle, position: 'absolute', background: 'black', color: 'white' }}>
I'm a tooltip!
</div>
</div>
);
}

// <Tooltip position="top"><button>Hover Me</button></Tooltip>

10. useDebugValue

用途: 用于在 React DevTools 中显示自定义 Hook 的标签。它不影响代码逻辑。

语法: useDebugValue(value, [format])

参数:

  • value: 要显示的值。
  • format (可选): 一个函数,用于格式化 value,只在 DevTools 面板打开时执行,避免性能开销。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import React, { useState, useDebugValue } from 'react';

function useOnlineStatus() {
const [isOnline, setIsOnline] = useState(true);

// 在 DevTools 中显示 'Online Status: Online' 或 'Online Status: Offline'
useDebugValue(isOnline, value => value ? 'Online' : 'Offline');

React.useEffect(() => {
const handleOnline = () => setIsOnline(true);
const handleOffline = () => setIsOnline(false);

window.addEventListener('online', handleOnline);
window.addEventListener('offline', handleOffline);

return () => {
window.removeEventListener('online', handleOnline);
window.removeEventListener('offline', handleOffline);
};
}, []);

return isOnline;
}

function StatusBar() {
const isOnline = useOnlineStatus();
return <h1>{isOnline ? '✅ Online' : '❌ Offline'}</h1>;
}

四、其他核心 API

1. ReactDOM.createPortal(child, container)

用途: 将子节点渲染到存在于父组件 DOM 层级之外的 DOM 节点。这在处理模态框 (Modals)、浮窗 (Tooltips)、加载指示器等需要脱离父元素样式或溢出限制的场景非常有用。

参数:

  • child: 可以是任何可渲染的 React 子元素 (例如 JSX)。
  • container: 一个 DOM 元素,React 会将 child 挂载到这个 DOM 元素下。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// Modal.jsx
import React from 'react';
import { createPortal } from 'react-dom';

const modalRoot = document.getElementById('modal-root'); // 假设 HTML 中有一个 <div id="modal-root"></div>

function Modal({ children, isOpen, onClose }) {
if (!isOpen) return null;

return createPortal(
<div style={{
position: 'fixed',
top: 0, left: 0, right: 0, bottom: 0,
backgroundColor: 'rgba(0,0,0,0.5)',
display: 'flex', alignItems: 'center', justifyContent: 'center'
}}>
<div style={{
background: 'white', padding: '20px', borderRadius: '5px'
}}>
{children}
<button onClick={onClose}>Close Modal</button>
</div>
</div>,
modalRoot // 将 Modal 的内容渲染到 modalRoot 节点
);
}

// App.jsx
function App() {
const [showModal, setShowModal] = React.useState(false);
return (
<div>
<h1>My App</h1>
<button onClick={() => setShowModal(true)}>Open Modal</button>
<Modal isOpen={showModal} onClose={() => setShowModal(false)}>
<h2>This is a modal!</h2>
<p>It's rendered outside the main app DOM tree.</p>
</Modal>
</div>
);
}

2. React.memo(Component, [arePropsEqual])

用途: 是一种高阶组件 (HOC),用于优化函数组件的性能。它会记住组件的渲染结果,如果 props 没有改变,则跳过重新渲染该组件。

参数:

  • Component: 要进行性能优化的函数组件。
  • arePropsEqual (可选): 一个函数,用于自定义比较 props。如果返回 true,表示 props 相同,跳过重新渲染;否则重新渲染。默认是浅比较。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import React, { memo, useState } from 'react';

// 未优化的子组件
const ExpensiveComponentUnoptimized = ({ count, name }) => {
console.log('ExpensiveComponentUnoptimized rendered');
return <p>Count: {count}, Name: {name}</p>;
};

// 使用 memo 优化的子组件
const ExpensiveComponent = memo(({ count, name }) => {
console.log('ExpensiveComponent (memoized) rendered');
return <p>Count: {count}, Name: {name}</p>;
});

function ParentComponentOptimize() {
const [parentCount, setParentCount] = useState(0);
const [parentName, setParentName] = useState('World');

return (
<div>
<h1>Parent Component</h1>
<button onClick={() => setParentCount(parentCount + 1)}>
Increment Parent Count ({parentCount})
</button>
<button onClick={() => setParentName(parentName === 'World' ? 'React' : 'World')}>
Change Parent Name ({parentName})
</button>

{/* 每次 ParentComponentOptimize 渲染,都会重新渲染 */}
<ExpensiveComponentUnoptimized count={parentCount} name={parentName} />

{/* 仅当 props (count, name) 发生变化时才重新渲染 */}
<ExpensiveComponent count={parentCount} name={parentName} />
</div>
);
}

3. React.forwardRef(render)

用途: 允许函数组件接收一个 ref,并将其向下转发给子组件内部的 DOM 节点或另一个 React 组件。

参数:

  • render: 一个渲染函数,接收 propsref 作为参数。

示例: (见 useImperativeHandle 示例,SmallInput 组件就是用 forwardRef 包裹的)

4. React.createContext(defaultValue)

用途: 创建一个 Context 对象。当 React 渲染一个订阅了这个 Context 对象的组件时,它会从组件树中离这个组件最近的 Provider 获取当前 Context 值。

参数:

  • defaultValue: 只有当组件没有对应的 Provider 时才会被使用。如果提供了 ProviderdefaultValue 不起作用。

返回值: 一个 Context 对象,包含 ProviderConsumer 组件。

示例: (见 useContext 示例)

5. React.lazy(loadComponent) + React.Suspense

用途:

  • React.lazy: 允许你以动态导入(import())的方式定义一个按需加载的组件。
  • React.Suspense: 允许在子组件(或组件树中的某个地方)完成异步加载时,展示一个回退 (fallback) UI。

这对于代码分割和优化初始加载性能非常有用。

语法:

  • const MyLazyComponent = React.lazy(() => import('./MyComponent'));
  • <Suspense fallback={<p>Loading...</p>}> ... </Suspense>

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import React, { Suspense } from 'react';

// 使用 React.lazy 动态导入组件
const LazyLoadedComponent = React.lazy(() => import('./LazyLoadedComponent'));

function AppWithLazyLoading() {
const [showLazy, setShowLazy] = React.useState(false);

return (
<div>
<h1>Main App</h1>
<button onClick={() => setShowLazy(true)}>Load Lazy Component</button>
{showLazy && (
// Suspense 边界,当 LazyLoadedComponent 正在加载时,显示 fallback
<Suspense fallback={<div>Loading lazy component...</div>}>
<LazyLoadedComponent />
</Suspense>
)}
</div>
);
}

// LazyLoadedComponent.jsx
// export default function LazyLoadedComponent() {
// return <p>I am a lazily loaded component!</p>;
// }

6. React.StrictMode

用途: 一个用于突出显示应用中潜在问题的工具。它不会渲染任何可见 UI,但会为其后代激活额外的检查和警告。

特性:

  • 在开发模式下,它会对以下行为发出警告:
    • 不安全的生命周期方法。
    • 使用过时的字符串 ref API。
    • 使用了废弃的 findDOMNode 方法。
    • 检测意外的副作用(双重调用 render 函数、useEffectsetup/cleanup 函数)。
    • 遗留 Context API。
  • 不会对生产环境产生影响。

示例:

1
2
3
4
5
6
7
8
9
10
11
import React from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';

const container = document.getElementById('root');
const root = createRoot(container);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);

五、总结与展望

React 的核心 API 旨在提供一套强大而灵活的工具集,以构建高性能和可维护的 UI。从基础的组件定义到现代的 Hooks,再到高级的 Portal、Memo 和 Suspense,React 持续演进,不断提升开发者的体验和应用的性能。

  • 函数组件 + Hooks: 已经成为 React 开发的首选范式,极大地简化了状态管理和副作用处理。
  • Virtual DOM: 保证了高效的 UI 更新。
  • 声明式编程: 让 UI 逻辑更清晰、更易于理解。
  • 组件化: 促进了代码复用和可维护性。

深入理解并熟练运用这些 API,是成为一名高效 React 开发者的关键。React 强大的生态系统和不断创新的特性,将继续为前端开发带来更多可能性。