React 18 核心特性详解:Props、State 与 Context 的深度实践
引言
React 18 作为最新版本,带来了 自动批处理 、并发模式优化 和 严格模式调整 等重要更新。本文将从 Props 、State 和 Context 三大核心概念入手,结合 React 18 的新特性,通过实战示例帮助开发者从基础到进阶全面掌握其应用。
一、Props:组件间的数据桥梁
1. 基础概念与作用
- 定义:Props 是父组件向子组件传递数据的机制,本质是一个不可变的对象。
- 特点 :
- 单向数据流:数据从父组件流向子组件。
- 只读性:子组件不能直接修改 Props,需通过回调函数通知父组件更新。
2. React 18 中的 Props 特性
(1)默认值与类型校验
jsx
import React from 'react';
import PropTypes from 'prop-types';
// 子组件:显示用户信息
function UserInfo(props) {
return (
<div>
<p>姓名:{props.name}</p >
<p>年龄:{props.age}</p >
</div>
);
}
// 设置默认值和类型校验
UserInfo.defaultProps = {
name: '匿名',
age: 18,
};
UserInfo.propTypes = {
name: PropTypes.string.isRequired,
age: PropTypes.number,
};
export default UserInfo;
(2)函数式组件的默认参数(推荐替代 defaultProps)
jsx
function UserInfo({ name = '匿名', age = 18 }) {
return (
<div>
<p>姓名:{name}</p >
<p>年龄:{age}</p >
</div>
);
}
3. 实战示例:动态表单输入
jsx
import React, { useState } from 'react';
// 子组件:带校验的输入框
function ValidatedInput({ value, onChange, error }) {
return (
<div>
<input
value={value}
onChange={(e) => onChange(e.target.value)}
placeholder="请输入文本"
/>
<p style={{ color: 'red' }}>{error}</p >
</div>
);
}
// 父组件:管理表单状态
function Form() {
const [inputValue, setInputValue] = useState('');
const [error, setError] = useState('');
const handleChange = (value) => {
if (value.trim() === '') {
setError('输入不能为空');
} else {
setError('');
}
setInputValue(value);
};
return (
<ValidatedInput
value={inputValue}
onChange={handleChange}
error={error}
/>
);
}
export default Form;
二、State:组件的内部状态管理
1. 基础概念与作用
- 定义:State 是组件内部可变的数据,用于控制组件的渲染和行为。
- 特点 :
- 私有性:状态属于组件自身,外部无法直接访问。
- 更新规则:必须通过
setState
或useState
更新,不可直接修改。
2. React 18 中的 State 特性
(1)自动批处理(Automatic Batching)
jsx
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
const handleClick = () => {
setCount(count + 1); // 操作1
setCount(count + 2); // 操作2(会被合并)
console.log('Renderings:', count);
};
return (
<div>
<button onClick={handleClick}>增加3</button>
<p>当前计数:{count}</p >
</div>
);
}
export default Counter;
(2)函数式组件与 Hooks
jsx
import React, { useState, useEffect } from 'react';
function Clock() {
const [time, setTime] = useState(new Date());
useEffect(() => {
const timer = setInterval(() => {
setTime(new Date());
}, 1000);
return () => clearInterval(timer); // 清理副作用
}, []);
return <p>当前时间:{time.toLocaleTimeString()}</p >;
}
export default Clock;
3. 实战示例: todoList
jsx
import React, { useState } from 'react';
// 子组件:任务项
function TaskItem({ task, onDelete }) {
return (
<li>
{task.text}
<button onClick={() => onDelete(task.id)}>删除</button>
</li>
);
}
// 父组件:任务管理
function TodoList() {
const [tasks, setTasks] = useState([]);
const [inputValue, setInputValue] = useState('');
const addTask = () => {
if (inputValue.trim()) {
setTasks([...tasks, { id: Date.now(), text: inputValue }]);
setInputValue('');
}
};
const deleteTask = (id) => {
setTasks(tasks.filter((t) => t.id !== id));
};
return (
<div>
<input
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
placeholder="添加任务"
/>
<button onClick={addTask}>添加</button>
<ul>
{tasks.map((task) => (
<TaskItem key={task.id} task={task} onDelete={deleteTask} />
))}
</ul>
</div>
);
}
export default TodoList;
三、Context:全局状态共享
1. 基础概念与作用
- 定义:Context 提供一种在组件树中全局共享数据的方式,无需逐层传递 Props。
- 适用场景:主题管理、用户认证、语言偏好等全局状态。
2. React 18 中的 Context 特性
(1)基本用法
jsx
import React, { createContext, useContext, useState } from 'react';
// 创建上下文
const ThemeContext = createContext();
// 主题提供者组件
function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{children}
</ThemeContext.Provider>
);
}
// 消费者组件
function ThemeSwitcher() {
const { theme, setTheme } = useContext(ThemeContext);
return (
<div>
<p>当前主题:{theme}</p >
<button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
切换主题
</button>
</div>
);
}
// 应用根组件
function App() {
return (
<ThemeProvider>
<ThemeSwitcher />
</ThemeProvider>
);
}
export default App;
(2)结合并发模式优化
jsx
import React, { Suspense, use } from 'react';
async function fetchData() {
const res = await fetch('/api/data');
return res.json();
}
function DataComponent() {
const data = use(fetchData()); // 并发加载数据
return <p>{JSON.stringify(data)}</p >;
}
function App() {
return (
<Suspense fallback={<p>Loading...</p >}>
<DataComponent />
</Suspense>
);
}
export default App;
3. 实战示例:全局用户状态
jsx
import React, { createContext, useContext, useEffect, useState } from 'react';
// 创建用户上下文
const UserContext = createContext();
// 用户提供者组件
function UserProvider({ children }) {
const [user, setUser] = useState(null);
useEffect(() => {
// 模拟登录流程
const loggedInUser = { id: 1, name: 'Alice' };
setTimeout(() => setUser(loggedInUser), 1000);
}, []);
return (
<UserContext.Provider value={{ user, setUser }}>
{children}
</UserContext.Provider>
);
}
// 消费者组件
function UserProfile() {
const { user } = useContext(UserContext);
if (!user) return <p>加载中...</p >;
return <p>已登录用户:{user.name}</p >;
}
// 应用根组件
function App() {
return (
<UserProvider>
<UserProfile />
</UserProvider>
);
}
export default App;
四、性能优化与最佳实践
1. 避免不必要的渲染
- 使用
React.memo
:缓存函数组件渲染结果。 - 使用
useCallback
:防止函数重新创建导致子组件重渲。
jsx
import React, { memo, useCallback } from 'react';
function ExpensiveComponent({ value }) {
console.log('渲染耗时组件');
return <p>{value}</p >;
}
function ParentComponent() {
const [count, setCount] = useState(0);
const handleClick = useCallback(() => setCount(count + 1), [count]);
return (
<>
<ExpensiveComponent value={count} />
<button onClick={handleClick}>增加</button>
</>
);
}
export default memo(ParentComponent);
2. 严格模式下的变更
- React 18 移除了
componentDidMount
的双重调用,需避免依赖旧行为的代码。 - 推荐使用
useEffect
代替生命周期方法。
五、总结与未来展望
React 18 通过 自动批处理 和 并发模式 进一步优化了性能,同时简化了状态管理逻辑。在实际开发中,建议:
- 优先使用函数式组件:结合 Hooks 实现更简洁的状态管理。
- 合理划分 Context 的粒度:避免全局状态滥用导致维护困难。
- 持续关注 React 提案:如 React Forget、Server Components 等新特性。
通过本文的示例,开发者可快速上手 React 18 的核心功能,并在实际项目中灵活应用。