
React18入门到精通教程
2023-02-21 18:01:52
2025-06-01 21:18:20
JSX实现列表渲染
使用
map()
方法遍历数组,必须添加key
属性提高性能
jsx
const songs = [
{ id: 1, name: "helo1" },
{ id: 2, name: "helo2" },
{ id: 3, name: "helo3" },
];
function App() {
return (
<div>
<ul>
{songs.map((song) => (
// 关键:添加唯一key标识符(避免使用索引)
<li key={song.id}>
{song.id}-{song.name}
</li>
))}
</ul>
</div>
);
}
最佳实践:
- 使用
<ul>
包裹列表项 key
应使用稳定唯一标识(如ID),避免数组索引- 空列表处理:
{songs.length > 0 && ...}
或{songs.map(...) || <EmptyView/>}
JSX实现条件渲染
简单逻辑
jsx
// 三元表达式
{isLoggedIn ? <Dashboard /> : <LoginForm />}
// 逻辑短路
{hasNotification && <NotificationBadge count={5} />}
// 空值处理
{userProfile?.avatar || <DefaultAvatar />}
复杂逻辑
jsx
const renderContent = (type) => {
switch(type) {
case 'success':
return <SuccessAlert />;
case 'error':
return <ErrorAlert />;
default:
return <InfoAlert />;
}
}
function App() {
return (
<div className="container">
{renderContent(status)}
{/* 另一种模式:立即执行函数 */}
{(() => {
if (isLoading) return <Spinner />;
if (isEmpty) return <EmptyState />;
return <DataTable />;
})()}
</div>
)
}
JSX样式处理
行内样式
jsx
// 直接对象
<div style={{
color: 'white',
backgroundColor: 'teal',
padding: '1rem'
}}>
// 样式对象复用
const alertStyle = {
padding: '15px',
borderRadius: '4px',
margin: '10px 0'
};
function Alert({ type }) {
return (
<div style={{
...alertStyle, // 扩展运算符合并样式
background: type === 'error' ? '#f8d7da' : '#d4edda'
}}>
{message}
</div>
)
}
类名控制(推荐)
css
/* styles.module.css */
.card {
border: 1px solid #ddd;
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.highlight {
background-color: #ffffe0;
}
jsx
import styles from './styles.module.css';
function ProductCard({ featured }) {
return (
<div className={`${styles.card} ${featured ? styles.highlight : ''}`}>
{/* 内容 */}
</div>
);
}
React 18新特性
并发模式(Concurrent Mode)
jsx
import { startTransition } from 'react';
// 非紧急状态更新
function handleSearch(query) {
startTransition(() => {
setSearchQuery(query); // 可中断的渲染
});
}
自动批处理(Automatic Batching)
jsx
// React 17及之前:两次渲染
// React 18:自动批处理,一次渲染
function handleClick() {
setCount(c => c + 1);
setFlag(f => !f);
}
Redux状态管理(现代写法)
安装依赖
bash
npm install @reduxjs/toolkit react-redux
创建Store
js
// store.js
import { configureStore, createSlice } from '@reduxjs/toolkit';
const counterSlice = createSlice({
name: 'counter',
initialState: { value: 0 },
reducers: {
increment: state => { state.value += 1 },
decrement: state => { state.value -= 1 },
incrementByAmount: (state, action) => {
state.value += action.payload
}
}
});
// 异步操作示例
export const fetchUserData = () => async (dispatch) => {
const response = await fetch('/api/user');
dispatch(setUser(await response.json()));
};
export const store = configureStore({
reducer: {
counter: counterSlice.reducer,
// 其他reducer...
}
});
export const { increment, decrement } = counterSlice.actions;
组件集成
jsx
// index.js
import { Provider } from 'react-redux';
import { store } from './store';
root.render(
<Provider store={store}>
<App />
</Provider>
);
// Counter.js
import { useSelector, useDispatch } from 'react-redux';
import { increment, decrement } from './store';
function Counter() {
const count = useSelector(state => state.counter.value);
const dispatch = useDispatch();
return (
<div>
<button onClick={() => dispatch(decrement())}>-</button>
<span>{count}</span>
<button onClick={() => dispatch(increment())}>+</button>
</div>
);
}
最佳实践总结
- 组件设计:遵循单一职责原则,拆分智能组件(容器组件)和展示组件
- 状态管理:
- 局部状态用
useState
/useReducer
- 全局共享状态用Redux
- 避免过度使用状态提升
- 局部状态用
- 性能优化:
- 使用
React.memo
记忆组件 - 使用
useCallback
/useMemo
避免不必要的重渲染 - 虚拟化长列表(react-window)
- 使用
- Hooks规范:
- 避免在循环/条件中使用Hook
- 自定义Hook以
use
前缀命名
- TypeScript集成:
tsx
interface UserCardProps { name: string; age: number; onSelect: (id: string) => void; } const UserCard: React.FC<UserCardProps> = ({ name, age }) => ( <div>{name} ({age})</div> )
下面为您完善教程,增加React路由和生命周期相关内容:
React路由管理(React Router v6)
安装与基础配置
bash
npm install react-router-dom@6
路由基础结构
jsx
// index.js
import { BrowserRouter } from 'react-router-dom';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<BrowserRouter>
<App />
</BrowserRouter>
);
// App.js
import { Routes, Route, Link } from 'react-router-dom';
function App() {
return (
<div>
<nav>
<Link to="/">首页</Link>
<Link to="/about">关于</Link>
<Link to="/users">用户列表</Link>
</nav>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/users" element={<UserList />} />
<Route path="/users/:id" element={<UserDetail />} />
<Route path="*" element={<NotFound />} />
</Routes>
</div>
);
}
嵌套路由
jsx
// Dashboard.js
import { Outlet } from 'react-router-dom';
function Dashboard() {
return (
<div>
<h2>仪表盘</h2>
<Outlet /> {/* 子路由渲染位置 */}
</div>
);
}
// 路由配置
<Routes>
<Route path="/dashboard" element={<Dashboard />}>
<Route index element={<DashboardHome />} />
<Route path="settings" element={<DashboardSettings />} />
<Route path="analytics" element={<DashboardAnalytics />} />
</Route>
</Routes>
编程式导航
jsx
import { useNavigate, useParams, useLocation } from 'react-router-dom';
function UserCard({ user }) {
const navigate = useNavigate();
return (
<div onClick={() => navigate(`/users/${user.id}`)}>
{user.name}
</div>
);
}
function UserDetail() {
const { id } = useParams(); // 获取URL参数
const location = useLocation(); // 获取位置对象
return (
<div>
<h2>用户ID: {id}</h2>
<p>当前路径: {location.pathname}</p>
</div>
);
}
路由守卫(认证保护)
jsx
import { Navigate } from 'react-router-dom';
function ProtectedRoute({ children }) {
const { isAuthenticated } = useAuth();
if (!isAuthenticated) {
return <Navigate to="/login" replace />;
}
return children;
}
// 使用
<Route
path="/dashboard"
element={
<ProtectedRoute>
<Dashboard />
</ProtectedRoute>
}
/>
React生命周期
类组件生命周期方法
jsx
class LifecycleDemo extends React.Component {
// 1. 初始化阶段
constructor(props) {
super(props);
this.state = { count: 0 };
console.log('Constructor');
}
// 2. 挂载阶段
componentDidMount() {
console.log('Component did mount');
// 适合进行API调用、事件订阅
this.timer = setInterval(() => {
this.setState(prev => ({ count: prev.count + 1 }));
}, 1000);
}
// 3. 更新阶段
shouldComponentUpdate(nextProps, nextState) {
console.log('Should component update?');
return nextState.count !== this.state.count;
}
componentDidUpdate(prevProps, prevState) {
console.log('Component did update');
}
// 4. 卸载阶段
componentWillUnmount() {
console.log('Component will unmount');
// 清理操作
clearInterval(this.timer);
}
render() {
console.log('Render');
return <div>Count: {this.state.count}</div>;
}
}
函数组件生命周期(Hooks实现)
jsx
import { useState, useEffect } from 'react';
function FunctionLifecycle() {
const [count, setCount] = useState(0);
const [data, setData] = useState(null);
// 相当于componentDidMount + componentDidUpdate
useEffect(() => {
console.log('每次渲染后执行');
});
// 相当于componentDidMount
useEffect(() => {
console.log('组件挂载后执行');
// 数据获取
fetch('/api/data')
.then(res => res.json())
.then(setData);
// 相当于componentWillUnmount
return () => {
console.log('组件卸载前执行');
};
}, []); // 空依赖数组
// 依赖变化时执行
useEffect(() => {
console.log('count变化时执行:', count);
document.title = `Count: ${count}`;
return () => {
console.log('清理count效果');
};
}, [count]); // count依赖
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(c => c + 1)}>增加</button>
{data && <pre>{JSON.stringify(data, null, 2)}</pre>}
</div>
);
}
生命周期阶段对比
阶段 | 类组件方法 | 函数组件Hook |
---|---|---|
挂载 | constructor | useState初始化 |
render | 函数体执行 | |
componentDidMount | useEffect(() => {}, []) | |
更新 | shouldComponentUpdate | React.memo, useMemo |
render | 函数体执行 | |
componentDidUpdate | useEffect(() => {}) | |
卸载 | componentWillUnmount | useEffect返回函数 |
错误处理 | componentDidCatch | 暂无直接等效,需错误边界组件 |
现代React开发建议
-
优先使用函数组件+Hooks:
- 90%的场景可替代类组件
- 更简洁的代码结构
- 更好的逻辑复用
-
关键生命周期替代:
componentDidMount
→useEffect(() => {}, [])
componentDidUpdate
→useEffect(() => {})
或带依赖的useEffect
componentWillUnmount
→useEffect(() => { return cleanup }, [])
shouldComponentUpdate
→React.memo
或useMemo
-
数据获取最佳实践:
jsx
useEffect(() => {
let isMounted = true;
const fetchData = async () => {
try {
const result = await api.getData();
if (isMounted) setData(result);
} catch (error) {
if (isMounted) setError(error);
}
};
fetchData();
return () => {
isMounted = false; // 避免组件卸载后设置状态
};
}, []);
路由与生命周期整合示例
jsx
function UserProfile() {
const { id } = useParams();
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
let isActive = true;
const fetchUser = async () => {
try {
setLoading(true);
const data = await fetchUserById(id);
if (isActive) {
setUser(data);
setLoading(false);
}
} catch (error) {
if (isActive) {
setError(error.message);
setLoading(false);
}
}
};
fetchUser();
return () => {
isActive = false; // 清理效果
};
}, [id]); // id变化时重新获取
if (loading) return <Spinner />;
return (
<div>
<h2>{user.name}</h2>
<p>Email: {user.email}</p>
</div>
);
}
完整项目结构建议
src/
├── components/ # 通用UI组件
├── pages/ # 页面组件
├── layouts/ # 布局组件
├── hooks/ # 自定义Hooks
├── store/ # Redux状态
│ ├── slices/
│ └── store.js
├── services/ # API服务
├── routers/ # 路由配置
├── utils/ # 工具函数
├── assets/ # 静态资源
└── App.js # 主应用组件
这些新增内容涵盖了React路由的现代用法(v6版本)以及React生命周期的详细解释,包括类组件和函数组件的实现方式对比。同时还提供了路由与生命周期整合的实际示例,帮助开发者理解如何在真实项目中应用这些概念。
目录