活动公告

系统通知
05-18 21:22
系统通知
通知:本站资源由网友上传分享,如有违规等问题请到版务模块进行投诉,资源失效请在帖子内回复要求补档,会尽快处理!
10-23 09:31

现代Web开发React框架JavaScript编程教程详解

SunJu_FaceMall

3万

主题

2860

科技点

3万

积分

白金月票

碾压王

积分
32872

塔罗立华奏

<font color=白金月票" /> 发表于 2025-9-5 23:00:01 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
现代Web开发React框架JavaScript编程教程详解

引言

React是由Facebook开发并开源的前端JavaScript库,用于构建用户界面,特别是单页应用程序。自2013年发布以来,React已经成为最受欢迎的前端框架之一,被无数大型网站和应用所采用。React的组件化架构、虚拟DOM和单向数据流等特性,使得开发复杂交互式Web应用变得更加高效和可维护。

本教程将全面介绍React框架的核心概念、实际应用和最佳实践,帮助读者从零开始掌握React开发,并能够构建现代化的Web应用程序。

React基础

JSX是JavaScript XML的缩写,它允许我们在JavaScript代码中编写类似HTML的语法。JSX使得编写React组件变得更加直观和简洁。
  1. // 基本的JSX语法
  2. const element = <h1>Hello, World!</h1>;
  3. // 使用表达式
  4. const name = 'John';
  5. const element = <h1>Hello, {name}</h1>;
  6. // JSX属性
  7. const element = <img src="avatar.jpg" alt="User Avatar" />;
  8. // 嵌套元素
  9. const element = (
  10.   <div>
  11.     <h1>Welcome</h1>
  12.     <p>This is a paragraph.</p>
  13.   </div>
  14. );
复制代码

需要注意的是,JSX并不是HTML,它在编译时会被转换为普通的JavaScript函数调用。React使用Babel来将JSX代码转换为React.createElement()调用。

React应用由组件构成,组件是可复用的、独立的UI单元。React中有两种类型的组件:函数组件和类组件。

函数组件是简单的JavaScript函数,接收props(属性)作为参数,并返回React元素。
  1. function Welcome(props) {
  2.   return <h1>Hello, {props.name}</h1>;
  3. }
  4. // 或者使用箭头函数
  5. const Welcome = (props) => {
  6.   return <h1>Hello, {props.name}</h1>;
  7. };
  8. // 更简洁的箭头函数形式
  9. const Welcome = (props) => <h1>Hello, {props.name}</h1>;
复制代码

类组件是继承自React.Component的ES6类,它们必须包含一个render()方法,用于返回React元素。
  1. class Welcome extends React.Component {
  2.   render() {
  3.     return <h1>Hello, {this.props.name}</h1>;
  4.   }
  5. }
复制代码

在现代React开发中,函数组件配合Hooks(将在后面介绍)成为主流,但了解类组件仍然很重要,特别是在维护旧代码时。

Props(属性)是父组件传递给子组件的数据。Props是只读的,子组件不能直接修改它们。
  1. function Welcome(props) {
  2.   return <h1>Hello, {props.name}</h1>;
  3. }
  4. function App() {
  5.   return <Welcome name="John" />;
  6. }
复制代码

State是组件内部维护的数据,当state发生变化时,组件会重新渲染。

在函数组件中,我们使用useStateHook来管理state:
  1. import React, { useState } from 'react';
  2. function Counter() {
  3.   // 声明一个新的state变量,初始值为0
  4.   const [count, setCount] = useState(0);
  5.   return (
  6.     <div>
  7.       <p>You clicked {count} times</p>
  8.       <button onClick={() => setCount(count + 1)}>
  9.         Click me
  10.       </button>
  11.     </div>
  12.   );
  13. }
复制代码

在类组件中,state通过构造函数初始化,并通过this.setState()方法更新:
  1. class Counter extends React.Component {
  2.   constructor(props) {
  3.     super(props);
  4.     this.state = { count: 0 };
  5.   }
  6.   render() {
  7.     return (
  8.       <div>
  9.         <p>You clicked {this.state.count} times</p>
  10.         <button onClick={() => this.setState({ count: this.state.count + 1 })}>
  11.           Click me
  12.         </button>
  13.       </div>
  14.     );
  15.   }
  16. }
复制代码

React核心概念

类组件有特定的生命周期方法,这些方法在组件的不同阶段被调用:

1. 挂载阶段:组件被创建并插入到DOM中constructor(): 组件构造函数static getDerivedStateFromProps(): 在渲染前调用,用于根据props更新staterender(): 渲染组件componentDidMount(): 组件挂载后调用,适合进行API调用等副作用操作
2. constructor(): 组件构造函数
3. static getDerivedStateFromProps(): 在渲染前调用,用于根据props更新state
4. render(): 渲染组件
5. componentDidMount(): 组件挂载后调用,适合进行API调用等副作用操作
6. 更新阶段:组件的props或state发生变化static getDerivedStateFromProps(): 在渲染前调用,用于根据props更新stateshouldComponentUpdate(): 决定组件是否应该重新渲染render(): 渲染组件getSnapshotBeforeUpdate(): 在DOM更新前调用,可以获取DOM更新前的信息componentDidUpdate(): 组件更新后调用
7. static getDerivedStateFromProps(): 在渲染前调用,用于根据props更新state
8. shouldComponentUpdate(): 决定组件是否应该重新渲染
9. render(): 渲染组件
10. getSnapshotBeforeUpdate(): 在DOM更新前调用,可以获取DOM更新前的信息
11. componentDidUpdate(): 组件更新后调用
12. 卸载阶段:组件从DOM中移除componentWillUnmount(): 组件卸载前调用,适合进行清理工作
13. componentWillUnmount(): 组件卸载前调用,适合进行清理工作

挂载阶段:组件被创建并插入到DOM中

• constructor(): 组件构造函数
• static getDerivedStateFromProps(): 在渲染前调用,用于根据props更新state
• render(): 渲染组件
• componentDidMount(): 组件挂载后调用,适合进行API调用等副作用操作

更新阶段:组件的props或state发生变化

• static getDerivedStateFromProps(): 在渲染前调用,用于根据props更新state
• shouldComponentUpdate(): 决定组件是否应该重新渲染
• render(): 渲染组件
• getSnapshotBeforeUpdate(): 在DOM更新前调用,可以获取DOM更新前的信息
• componentDidUpdate(): 组件更新后调用

卸载阶段:组件从DOM中移除

• componentWillUnmount(): 组件卸载前调用,适合进行清理工作
  1. class LifecycleDemo extends React.Component {
  2.   constructor(props) {
  3.     super(props);
  4.     this.state = { count: 0 };
  5.     console.log('Constructor called');
  6.   }
  7.   componentDidMount() {
  8.     console.log('Component mounted');
  9.     // 可以在这里进行API调用
  10.     document.title = `You clicked ${this.state.count} times`;
  11.   }
  12.   componentDidUpdate(prevProps, prevState) {
  13.     console.log('Component updated');
  14.     // 可以在这里根据state变化进行操作
  15.     if (prevState.count !== this.state.count) {
  16.       document.title = `You clicked ${this.state.count} times`;
  17.     }
  18.   }
  19.   componentWillUnmount() {
  20.     console.log('Component will unmount');
  21.     // 清理工作,如清除定时器
  22.   }
  23.   render() {
  24.     console.log('Component rendered');
  25.     return (
  26.       <div>
  27.         <p>You clicked {this.state.count} times</p>
  28.         <button onClick={() => this.setState({ count: this.state.count + 1 })}>
  29.           Click me
  30.         </button>
  31.       </div>
  32.     );
  33.   }
  34. }
复制代码

Hooks是React 16.8引入的新特性,它允许你在不编写类组件的情况下使用state和其他React特性。Hooks只能在函数组件的顶层调用,不能在条件语句、循环或嵌套函数中调用。

useState用于在函数组件中添加state。
  1. import React, { useState } from 'react';
  2. function Counter() {
  3.   const [count, setCount] = useState(0);
  4.   // 可以有多个state变量
  5.   const [name, setName] = useState('John');
  6.   return (
  7.     <div>
  8.       <p>You clicked {count} times</p>
  9.       <button onClick={() => setCount(count + 1)}>
  10.         Click me
  11.       </button>
  12.       <p>Hello, {name}</p>
  13.       <button onClick={() => setName('Jane')}>
  14.         Change name
  15.       </button>
  16.     </div>
  17.   );
  18. }
复制代码

useEffect用于处理副作用,如API调用、订阅、手动操作DOM等。它相当于类组件中的componentDidMount、componentDidUpdate和componentWillUnmount的组合。
  1. import React, { useState, useEffect } from 'react';
  2. function Example() {
  3.   const [count, setCount] = useState(0);
  4.   // 类似于componentDidMount和componentDidUpdate
  5.   useEffect(() => {
  6.     // 更新文档标题
  7.     document.title = `You clicked ${count} times`;
  8.   });
  9.   // 只在挂载时执行一次,类似于componentDidMount
  10.   useEffect(() => {
  11.     console.log('Component mounted');
  12.     // 可以在这里进行API调用
  13.     fetch('https://api.example.com/data')
  14.       .then(response => response.json())
  15.       .then(data => console.log(data));
  16.   }, []); // 空依赖数组表示只在挂载时执行
  17.   // 在count变化时执行,类似于componentDidUpdate
  18.   useEffect(() => {
  19.     console.log('Count changed:', count);
  20.   }, [count]); // 依赖数组包含count,表示count变化时执行
  21.   // 清理副作用,类似于componentWillUnmount
  22.   useEffect(() => {
  23.     const timer = setInterval(() => {
  24.       console.log('Timer tick');
  25.     }, 1000);
  26.     // 返回的函数会在组件卸载时执行
  27.     return () => {
  28.       clearInterval(timer);
  29.       console.log('Timer cleared');
  30.     };
  31.   }, []);
  32.   return (
  33.     <div>
  34.       <p>You clicked {count} times</p>
  35.       <button onClick={() => setCount(count + 1)}>
  36.         Click me
  37.       </button>
  38.     </div>
  39.   );
  40. }
复制代码

useContext用于在组件间共享数据,避免props层层传递。
  1. import React, { createContext, useContext, useState } from 'react';
  2. // 创建Context
  3. const ThemeContext = createContext();
  4. function App() {
  5.   const [theme, setTheme] = useState('light');
  6.   return (
  7.     // 使用Provider提供值
  8.     <ThemeContext.Provider value={{ theme, setTheme }}>
  9.       <Toolbar />
  10.     </ThemeContext.Provider>
  11.   );
  12. }
  13. function Toolbar() {
  14.   return (
  15.     <div>
  16.       <ThemedButton />
  17.     </div>
  18.   );
  19. }
  20. function ThemedButton() {
  21.   // 使用Consumer获取值
  22.   const { theme, setTheme } = useContext(ThemeContext);
  23.   return (
  24.     <button
  25.       style={{ background: theme === 'light' ? '#fff' : '#333', color: theme === 'light' ? '#333' : '#fff' }}
  26.       onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}
  27.     >
  28.       Toggle Theme
  29.     </button>
  30.   );
  31. }
复制代码

useReducer是useState的替代方案,适用于复杂的state逻辑。
  1. import React, { useReducer } from 'react';
  2. // 定义reducer函数
  3. function reducer(state, action) {
  4.   switch (action.type) {
  5.     case 'increment':
  6.       return { count: state.count + 1 };
  7.     case 'decrement':
  8.       return { count: state.count - 1 };
  9.     default:
  10.       throw new Error();
  11.   }
  12. }
  13. function Counter() {
  14.   // 使用useReducer
  15.   const [state, dispatch] = useReducer(reducer, { count: 0 });
  16.   return (
  17.     <>
  18.       Count: {state.count}
  19.       <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
  20.       <button onClick={() => dispatch({ type: 'increment' })}>+</button>
  21.     </>
  22.   );
  23. }
复制代码

自定义Hooks是一种复用状态逻辑的机制,它允许你将组件逻辑提取到可重用的函数中。
  1. import { useState, useEffect } from 'react';
  2. // 自定义Hook:处理窗口大小变化
  3. function useWindowWidth() {
  4.   const [width, setWidth] = useState(window.innerWidth);
  5.   useEffect(() => {
  6.     const handleResize = () => setWidth(window.innerWidth);
  7.     window.addEventListener('resize', handleResize);
  8.    
  9.     return () => {
  10.       window.removeEventListener('resize', handleResize);
  11.     };
  12.   }, []);
  13.   return width;
  14. }
  15. // 使用自定义Hook
  16. function ResponsiveComponent() {
  17.   const width = useWindowWidth();
  18.   return (
  19.     <div>
  20.       Current window width: {width}px
  21.       {width < 768 ? <MobileView /> : <DesktopView />}
  22.     </div>
  23.   );
  24. }
  25. function MobileView() {
  26.   return <div>This is mobile view</div>;
  27. }
  28. function DesktopView() {
  29.   return <div>This is desktop view</div>;
  30. }
复制代码

Context提供了一种在组件树中共享数据的方式,而不必通过props逐层传递。当多个组件需要访问相同的数据时,Context非常有用。
  1. import React, { createContext, useContext, useState } from 'react';
  2. // 创建Context
  3. const UserContext = createContext();
  4. function App() {
  5.   const [user, setUser] = useState({ name: 'John', age: 30 });
  6.   return (
  7.     // 使用Provider提供值
  8.     <UserContext.Provider value={{ user, setUser }}>
  9.       <Profile />
  10.       <UpdateUser />
  11.     </UserContext.Provider>
  12.   );
  13. }
  14. function Profile() {
  15.   // 使用Consumer获取值
  16.   const { user } = useContext(UserContext);
  17.   return (
  18.     <div>
  19.       <h2>Profile</h2>
  20.       <p>Name: {user.name}</p>
  21.       <p>Age: {user.age}</p>
  22.     </div>
  23.   );
  24. }
  25. function UpdateUser() {
  26.   const { user, setUser } = useContext(UserContext);
  27.   const updateName = () => {
  28.     setUser({ ...user, name: 'Jane' });
  29.   };
  30.   return (
  31.     <div>
  32.       <h2>Update User</h2>
  33.       <button onClick={updateName}>Change Name to Jane</button>
  34.     </div>
  35.   );
  36. }
复制代码

路由与导航

在单页应用中,路由是实现不同页面间导航的关键。React Router是React中最流行的路由库。
  1. npm install react-router-dom
复制代码
  1. import React from 'react';
  2. import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom';
  3. function App() {
  4.   return (
  5.     <Router>
  6.       <div>
  7.         <nav>
  8.           <ul>
  9.             <li><Link to="/">Home</Link></li>
  10.             <li><Link to="/about">About</Link></li>
  11.             <li><Link to="/users">Users</Link></li>
  12.           </ul>
  13.         </nav>
  14.         <Routes>
  15.           <Route path="/" element={<Home />} />
  16.           <Route path="/about" element={<About />} />
  17.           <Route path="/users" element={<Users />} />
  18.         </Routes>
  19.       </div>
  20.     </Router>
  21.   );
  22. }
  23. function Home() {
  24.   return <h2>Home</h2>;
  25. }
  26. function About() {
  27.   return <h2>About</h2>;
  28. }
  29. function Users() {
  30.   return <h2>Users</h2>;
  31. }
复制代码
  1. import React from 'react';
  2. import { BrowserRouter as Router, Routes, Route, Link, useParams } from 'react-router-dom';
  3. function App() {
  4.   return (
  5.     <Router>
  6.       <div>
  7.         <nav>
  8.           <ul>
  9.             <li><Link to="/">Home</Link></li>
  10.             <li><Link to="/users">Users</Link></li>
  11.           </ul>
  12.         </nav>
  13.         <Routes>
  14.           <Route path="/" element={<Home />} />
  15.           <Route path="/users" element={<Users />} />
  16.           <Route path="/users/:id" element={<UserDetail />} />
  17.         </Routes>
  18.       </div>
  19.     </Router>
  20.   );
  21. }
  22. function Home() {
  23.   return <h2>Home</h2>;
  24. }
  25. function Users() {
  26.   const users = [
  27.     { id: 1, name: 'John' },
  28.     { id: 2, name: 'Jane' },
  29.     { id: 3, name: 'Bob' }
  30.   ];
  31.   return (
  32.     <div>
  33.       <h2>Users</h2>
  34.       <ul>
  35.         {users.map(user => (
  36.           <li key={user.id}>
  37.             <Link to={`/users/${user.id}`}>{user.name}</Link>
  38.           </li>
  39.         ))}
  40.       </ul>
  41.     </div>
  42.   );
  43. }
  44. function UserDetail() {
  45.   // 获取URL参数
  46.   const { id } = useParams();
  47.   
  48.   // 模拟根据ID获取用户数据
  49.   const users = {
  50.     1: { name: 'John', email: 'john@example.com' },
  51.     2: { name: 'Jane', email: 'jane@example.com' },
  52.     3: { name: 'Bob', email: 'bob@example.com' }
  53.   };
  54.   
  55.   const user = users[id];
  56.   if (!user) {
  57.     return <div>User not found</div>;
  58.   }
  59.   return (
  60.     <div>
  61.       <h2>User Detail</h2>
  62.       <p>Name: {user.name}</p>
  63.       <p>Email: {user.email}</p>
  64.       <Link to="/users">Back to Users</Link>
  65.     </div>
  66.   );
  67. }
复制代码
  1. import React from 'react';
  2. import { BrowserRouter as Router, Routes, Route, Link, Outlet } from 'react-router-dom';
  3. function App() {
  4.   return (
  5.     <Router>
  6.       <div>
  7.         <nav>
  8.           <ul>
  9.             <li><Link to="/">Home</Link></li>
  10.             <li><Link to="/products">Products</Link></li>
  11.           </ul>
  12.         </nav>
  13.         <Routes>
  14.           <Route path="/" element={<Home />} />
  15.           <Route path="products" element={<Products />}>
  16.             <Route path="featured" element={<FeaturedProducts />} />
  17.             <Route path="new" element={<NewProducts />} />
  18.           </Route>
  19.         </Routes>
  20.       </div>
  21.     </Router>
  22.   );
  23. }
  24. function Home() {
  25.   return <h2>Home</h2>;
  26. }
  27. function Products() {
  28.   return (
  29.     <div>
  30.       <h2>Products</h2>
  31.       <nav>
  32.         <ul>
  33.           <li><Link to="/products/featured">Featured Products</Link></li>
  34.           <li><Link to="/products/new">New Products</Link></li>
  35.         </ul>
  36.       </nav>
  37.       {/* 嵌套路由的渲染位置 */}
  38.       <Outlet />
  39.     </div>
  40.   );
  41. }
  42. function FeaturedProducts() {
  43.   return <h3>Featured Products</h3>;
  44. }
  45. function NewProducts() {
  46.   return <h3>New Products</h3>;
  47. }
复制代码
  1. import React from 'react';
  2. import { BrowserRouter as Router, Routes, Route, useNavigate } from 'react-router-dom';
  3. function App() {
  4.   return (
  5.     <Router>
  6.       <Routes>
  7.         <Route path="/" element={<Home />} />
  8.         <Route path="/about" element={<About />} />
  9.         <Route path="/contact" element={<Contact />} />
  10.       </Routes>
  11.     </Router>
  12.   );
  13. }
  14. function Home() {
  15.   const navigate = useNavigate();
  16.   const goToAbout = () => {
  17.     navigate('/about');
  18.   };
  19.   return (
  20.     <div>
  21.       <h2>Home</h2>
  22.       <button onClick={goToAbout}>Go to About</button>
  23.     </div>
  24.   );
  25. }
  26. function About() {
  27.   const navigate = useNavigate();
  28.   const goToContact = () => {
  29.     navigate('/contact');
  30.   };
  31.   const goBack = () => {
  32.     navigate(-1); // 返回上一页
  33.   };
  34.   return (
  35.     <div>
  36.       <h2>About</h2>
  37.       <button onClick={goToContact}>Go to Contact</button>
  38.       <button onClick={goBack}>Go Back</button>
  39.     </div>
  40.   );
  41. }
  42. function Contact() {
  43.   return <h2>Contact</h2>;
  44. }
复制代码

状态管理

随着应用规模的扩大,组件间的状态共享和管理变得越来越复杂。虽然React的Context API可以解决一些问题,但对于大型应用,使用专门的状态管理库会更加高效。

Redux是一个可预测的状态容器,用于JavaScript应用。它可以帮助你管理应用的全局状态。
  1. npm install redux react-redux
复制代码
  1. import React from 'react';
  2. import { createStore } from 'redux';
  3. import { Provider, useSelector, useDispatch } from 'react-redux';
  4. // 1. 定义action类型
  5. const INCREMENT = 'INCREMENT';
  6. const DECREMENT = 'DECREMENT';
  7. // 2. 定义action creators
  8. const increment = () => ({ type: INCREMENT });
  9. const decrement = () => ({ type: DECREMENT });
  10. // 3. 定义reducer
  11. function counterReducer(state = { count: 0 }, action) {
  12.   switch (action.type) {
  13.     case INCREMENT:
  14.       return { count: state.count + 1 };
  15.     case DECREMENT:
  16.       return { count: state.count - 1 };
  17.     default:
  18.       return state;
  19.   }
  20. }
  21. // 4. 创建store
  22. const store = createStore(counterReducer);
  23. function App() {
  24.   return (
  25.     // 5. 使用Provider提供store
  26.     <Provider store={store}>
  27.       <Counter />
  28.     </Provider>
  29.   );
  30. }
  31. function Counter() {
  32.   // 6. 使用useSelector获取state
  33.   const count = useSelector(state => state.count);
  34.   
  35.   // 7. 使用useDispatch获取dispatch函数
  36.   const dispatch = useDispatch();
  37.   return (
  38.     <div>
  39.       <h1>Counter: {count}</h1>
  40.       <button onClick={() => dispatch(increment())}>Increment</button>
  41.       <button onClick={() => dispatch(decrement())}>Decrement</button>
  42.     </div>
  43.   );
  44. }
复制代码

Redux Toolkit是Redux官方推荐的工具集,它简化了Redux的设置和使用。
  1. npm install @reduxjs/toolkit react-redux
复制代码
  1. import React from 'react';
  2. import { configureStore, createSlice } from '@reduxjs/toolkit';
  3. import { Provider, useSelector, useDispatch } from 'react-redux';
  4. // 1. 创建slice
  5. const counterSlice = createSlice({
  6.   name: 'counter',
  7.   initialState: { count: 0 },
  8.   reducers: {
  9.     increment: (state) => {
  10.       state.count += 1;
  11.     },
  12.     decrement: (state) => {
  13.       state.count -= 1;
  14.     },
  15.     incrementByAmount: (state, action) => {
  16.       state.count += action.payload;
  17.     }
  18.   }
  19. });
  20. // 导出action creators
  21. export const { increment, decrement, incrementByAmount } = counterSlice.actions;
  22. // 2. 配置store
  23. const store = configureStore({
  24.   reducer: {
  25.     counter: counterSlice.reducer
  26.   }
  27. });
  28. function App() {
  29.   return (
  30.     <Provider store={store}>
  31.       <Counter />
  32.     </Provider>
  33.   );
  34. }
  35. function Counter() {
  36.   const count = useSelector((state) => state.counter.count);
  37.   const dispatch = useDispatch();
  38.   return (
  39.     <div>
  40.       <h1>Counter: {count}</h1>
  41.       <button onClick={() => dispatch(increment())}>Increment</button>
  42.       <button onClick={() => dispatch(decrement())}>Decrement</button>
  43.       <button onClick={() => dispatch(incrementByAmount(5))}>Increment by 5</button>
  44.     </div>
  45.   );
  46. }
复制代码

Redux Thunk是一个中间件,允许你在Redux应用中编写异步逻辑。
  1. npm install redux-thunk
复制代码
  1. import React, { useEffect } from 'react';
  2. import { configureStore, createSlice } from '@reduxjs/toolkit';
  3. import { Provider, useSelector, useDispatch } from 'react-redux';
  4. import thunk from 'redux-thunk';
  5. // 用户slice
  6. const userSlice = createSlice({
  7.   name: 'user',
  8.   initialState: { user: null, loading: false, error: null },
  9.   reducers: {
  10.     fetchUserStart: (state) => {
  11.       state.loading = true;
  12.       state.error = null;
  13.     },
  14.     fetchUserSuccess: (state, action) => {
  15.       state.loading = false;
  16.       state.user = action.payload;
  17.     },
  18.     fetchUserFailure: (state, action) => {
  19.       state.loading = false;
  20.       state.error = action.payload;
  21.     }
  22.   }
  23. });
  24. export const { fetchUserStart, fetchUserSuccess, fetchUserFailure } = userSlice.actions;
  25. // 异步action creator
  26. export const fetchUser = (id) => {
  27.   return async (dispatch) => {
  28.     dispatch(fetchUserStart());
  29.    
  30.     try {
  31.       const response = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);
  32.       const data = await response.json();
  33.       dispatch(fetchUserSuccess(data));
  34.     } catch (error) {
  35.       dispatch(fetchUserFailure(error.message));
  36.     }
  37.   };
  38. };
  39. // 配置store
  40. const store = configureStore({
  41.   reducer: {
  42.     user: userSlice.reducer
  43.   },
  44.   middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(thunk)
  45. });
  46. function App() {
  47.   return (
  48.     <Provider store={store}>
  49.       <UserProfile />
  50.     </Provider>
  51.   );
  52. }
  53. function UserProfile() {
  54.   const { user, loading, error } = useSelector((state) => state.user);
  55.   const dispatch = useDispatch();
  56.   useEffect(() => {
  57.     dispatch(fetchUser(1));
  58.   }, [dispatch]);
  59.   if (loading) return <div>Loading...</div>;
  60.   if (error) return <div>Error: {error}</div>;
  61.   if (!user) return null;
  62.   return (
  63.     <div>
  64.       <h1>User Profile</h1>
  65.       <p>Name: {user.name}</p>
  66.       <p>Email: {user.email}</p>
  67.       <p>Website: {user.website}</p>
  68.     </div>
  69.   );
  70. }
复制代码

MobX是另一个流行的状态管理库,它采用响应式编程模型,相比Redux更加简洁和直观。
  1. npm install mobx mobx-react-lite
复制代码
  1. import React from 'react';
  2. import { makeAutoObservable } from 'mobx';
  3. import { observer } from 'mobx-react-lite';
  4. // 1. 创建store
  5. class CounterStore {
  6.   count = 0;
  7.   constructor() {
  8.     makeAutoObservable(this);
  9.   }
  10.   increment() {
  11.     this.count += 1;
  12.   }
  13.   decrement() {
  14.     this.count -= 1;
  15.   }
  16. }
  17. // 2. 实例化store
  18. const counterStore = new CounterStore();
  19. // 3. 创建组件并使用observer包装
  20. const Counter = observer(() => {
  21.   return (
  22.     <div>
  23.       <h1>Counter: {counterStore.count}</h1>
  24.       <button onClick={() => counterStore.increment()}>Increment</button>
  25.       <button onClick={() => counterStore.decrement()}>Decrement</button>
  26.     </div>
  27.   );
  28. });
  29. function App() {
  30.   return <Counter />;
  31. }
复制代码

与后端交互

现代Web应用通常需要与后端API进行交互,获取和提交数据。React中有多种方式可以实现这一点。

Fetch API是现代浏览器内置的用于网络请求的接口。
  1. import React, { useState, useEffect } from 'react';
  2. function UserList() {
  3.   const [users, setUsers] = useState([]);
  4.   const [loading, setLoading] = useState(true);
  5.   const [error, setError] = useState(null);
  6.   useEffect(() => {
  7.     // 使用fetch获取数据
  8.     fetch('https://jsonplaceholder.typicode.com/users')
  9.       .then(response => {
  10.         if (!response.ok) {
  11.           throw new Error('Network response was not ok');
  12.         }
  13.         return response.json();
  14.       })
  15.       .then(data => {
  16.         setUsers(data);
  17.         setLoading(false);
  18.       })
  19.       .catch(error => {
  20.         setError(error.message);
  21.         setLoading(false);
  22.       });
  23.   }, []);
  24.   if (loading) return <div>Loading...</div>;
  25.   if (error) return <div>Error: {error}</div>;
  26.   return (
  27.     <div>
  28.       <h1>User List</h1>
  29.       <ul>
  30.         {users.map(user => (
  31.           <li key={user.id}>
  32.             {user.name} - {user.email}
  33.           </li>
  34.         ))}
  35.       </ul>
  36.     </div>
  37.   );
  38. }
复制代码

Axios是一个流行的HTTP客户端,它提供了比Fetch API更丰富的功能。
  1. npm install axios
复制代码
  1. import React, { useState, useEffect } from 'react';
  2. import axios from 'axios';
  3. function UserList() {
  4.   const [users, setUsers] = useState([]);
  5.   const [loading, setLoading] = useState(true);
  6.   const [error, setError] = useState(null);
  7.   useEffect(() => {
  8.     // 使用axios获取数据
  9.     axios.get('https://jsonplaceholder.typicode.com/users')
  10.       .then(response => {
  11.         setUsers(response.data);
  12.         setLoading(false);
  13.       })
  14.       .catch(error => {
  15.         setError(error.message);
  16.         setLoading(false);
  17.       });
  18.   }, []);
  19.   if (loading) return <div>Loading...</div>;
  20.   if (error) return <div>Error: {error}</div>;
  21.   return (
  22.     <div>
  23.       <h1>User List</h1>
  24.       <ul>
  25.         {users.map(user => (
  26.           <li key={user.id}>
  27.             {user.name} - {user.email}
  28.           </li>
  29.         ))}
  30.       </ul>
  31.     </div>
  32.   );
  33. }
复制代码
  1. import React, { useState } from 'react';
  2. import axios from 'axios';
  3. function CreateUser() {
  4.   const [name, setName] = useState('');
  5.   const [email, setEmail] = useState('');
  6.   const [loading, setLoading] = useState(false);
  7.   const [error, setError] = useState(null);
  8.   const [success, setSuccess] = useState(false);
  9.   const handleSubmit = (e) => {
  10.     e.preventDefault();
  11.     setLoading(true);
  12.     setError(null);
  13.     setSuccess(false);
  14.     const newUser = {
  15.       name,
  16.       email,
  17.       username: name.toLowerCase().replace(/\s+/g, '')
  18.     };
  19.     axios.post('https://jsonplaceholder.typicode.com/users', newUser)
  20.       .then(response => {
  21.         console.log('User created:', response.data);
  22.         setSuccess(true);
  23.         setName('');
  24.         setEmail('');
  25.         setLoading(false);
  26.       })
  27.       .catch(error => {
  28.         setError(error.message);
  29.         setLoading(false);
  30.       });
  31.   };
  32.   return (
  33.     <div>
  34.       <h1>Create User</h1>
  35.       {success && <div style={{ color: 'green' }}>User created successfully!</div>}
  36.       {error && <div style={{ color: 'red' }}>Error: {error}</div>}
  37.       <form onSubmit={handleSubmit}>
  38.         <div>
  39.           <label>Name:</label>
  40.           <input
  41.             type="text"
  42.             value={name}
  43.             onChange={(e) => setName(e.target.value)}
  44.             required
  45.           />
  46.         </div>
  47.         <div>
  48.           <label>Email:</label>
  49.           <input
  50.             type="email"
  51.             value={email}
  52.             onChange={(e) => setEmail(e.target.value)}
  53.             required
  54.           />
  55.         </div>
  56.         <button type="submit" disabled={loading}>
  57.           {loading ? 'Creating...' : 'Create User'}
  58.         </button>
  59.       </form>
  60.     </div>
  61.   );
  62. }
复制代码

React Query是一个强大的数据获取库,它提供了缓存、后台更新、乐观更新等功能。
  1. npm install react-query
复制代码
  1. import React from 'react';
  2. import { QueryClient, QueryClientProvider, useQuery } from 'react-query';
  3. import axios from 'axios';
  4. // 创建QueryClient
  5. const queryClient = new QueryClient();
  6. // 获取用户数据的函数
  7. const fetchUsers = async () => {
  8.   const { data } = await axios.get('https://jsonplaceholder.typicode.com/users');
  9.   return data;
  10. };
  11. function UserList() {
  12.   // 使用useQuery获取数据
  13.   const { data: users, isLoading, error } = useQuery('users', fetchUsers);
  14.   if (isLoading) return <div>Loading...</div>;
  15.   if (error) return <div>Error: {error.message}</div>;
  16.   return (
  17.     <div>
  18.       <h1>User List</h1>
  19.       <ul>
  20.         {users.map(user => (
  21.           <li key={user.id}>
  22.             {user.name} - {user.email}
  23.           </li>
  24.         ))}
  25.       </ul>
  26.     </div>
  27.   );
  28. }
  29. function App() {
  30.   return (
  31.     // 使用QueryClientProvider提供QueryClient
  32.     <QueryClientProvider client={queryClient}>
  33.       <UserList />
  34.     </QueryClientProvider>
  35.   );
  36. }
复制代码

样式处理

在React应用中,有多种方式可以处理组件样式。每种方法都有其优缺点,适用于不同的场景。

内联样式是直接在JSX元素上使用style属性定义样式。
  1. function Button() {
  2.   const buttonStyle = {
  3.     backgroundColor: '#4CAF50',
  4.     border: 'none',
  5.     color: 'white',
  6.     padding: '15px 32px',
  7.     textAlign: 'center',
  8.     textDecoration: 'none',
  9.     display: 'inline-block',
  10.     fontSize: '16px',
  11.     margin: '4px 2px',
  12.     cursor: 'pointer',
  13.     borderRadius: '4px'
  14.   };
  15.   return <button style={buttonStyle}>Click Me</button>;
  16. }
复制代码

CSS Modules允许你将CSS文件限定在特定组件范围内,避免全局样式冲突。
  1. /* Button.module.css */
  2. .button {
  3.   background-color: #4CAF50;
  4.   border: none;
  5.   color: white;
  6.   padding: 15px 32px;
  7.   text-align: center;
  8.   text-decoration: none;
  9.   display: inline-block;
  10.   font-size: 16px;
  11.   margin: 4px 2px;
  12.   cursor: pointer;
  13.   border-radius: 4px;
  14. }
  15. .button:hover {
  16.   background-color: #45a049;
  17. }
复制代码
  1. import React from 'react';
  2. import styles from './Button.module.css';
  3. function Button() {
  4.   return <button className={styles.button}>Click Me</button>;
  5. }
复制代码

Styled Components是一个流行的CSS-in-JS库,它允许你在JavaScript中编写CSS。
  1. npm install styled-components
复制代码
  1. import React from 'react';
  2. import styled from 'styled-components';
  3. // 创建styled组件
  4. const StyledButton = styled.button`
  5.   background-color: ${props => props.primary ? '#4CAF50' : 'white'};
  6.   color: ${props => props.primary ? 'white' : '#4CAF50'};
  7.   border: 2px solid #4CAF50;
  8.   padding: 15px 32px;
  9.   text-align: center;
  10.   text-decoration: none;
  11.   display: inline-block;
  12.   font-size: 16px;
  13.   margin: 4px 2px;
  14.   cursor: pointer;
  15.   border-radius: 4px;
  16.   
  17.   &:hover {
  18.     background-color: ${props => props.primary ? '#45a049' : '#f1f1f1'};
  19.   }
  20. `;
  21. function Button() {
  22.   return (
  23.     <div>
  24.       <StyledButton>Normal Button</StyledButton>
  25.       <StyledButton primary>Primary Button</StyledButton>
  26.     </div>
  27.   );
  28. }
复制代码

Emotion是另一个流行的CSS-in-JS库,它提供了强大的样式解决方案。
  1. npm install @emotion/react @emotion/styled
复制代码
  1. import React from 'react';
  2. import styled from '@emotion/styled';
  3. // 创建styled组件
  4. const StyledButton = styled.button`
  5.   background-color: ${props => props.primary ? '#4CAF50' : 'white'};
  6.   color: ${props => props.primary ? 'white' : '#4CAF50'};
  7.   border: 2px solid #4CAF50;
  8.   padding: 15px 32px;
  9.   text-align: center;
  10.   text-decoration: none;
  11.   display: inline-block;
  12.   font-size: 16px;
  13.   margin: 4px 2px;
  14.   cursor: pointer;
  15.   border-radius: 4px;
  16.   
  17.   &:hover {
  18.     background-color: ${props => props.primary ? '#45a049' : '#f1f1f1'};
  19.   }
  20. `;
  21. function Button() {
  22.   return (
  23.     <div>
  24.       <StyledButton>Normal Button</StyledButton>
  25.       <StyledButton primary>Primary Button</StyledButton>
  26.     </div>
  27.   );
  28. }
复制代码

Tailwind CSS是一个实用程序优先的CSS框架,它提供了低级别的实用程序类来构建自定义设计。
  1. npm install tailwindcss postcss autoprefixer
  2. npx tailwindcss init -p
复制代码
  1. // tailwind.config.js
  2. module.exports = {
  3.   content: [
  4.     "./src/**/*.{js,jsx,ts,tsx}",
  5.   ],
  6.   theme: {
  7.     extend: {},
  8.   },
  9.   plugins: [],
  10. }
复制代码
  1. /* src/index.css */
  2. @tailwind base;
  3. @tailwind components;
  4. @tailwind utilities;
复制代码
  1. import React from 'react';
  2. function Button() {
  3.   return (
  4.     <div>
  5.       <button className="bg-white text-green-500 border-2 border-green-500 px-8 py-4 text-base m-2 rounded cursor-pointer hover:bg-gray-100">
  6.         Normal Button
  7.       </button>
  8.       <button className="bg-green-500 text-white border-2 border-green-500 px-8 py-4 text-base m-2 rounded cursor-pointer hover:bg-green-600">
  9.         Primary Button
  10.       </button>
  11.     </div>
  12.   );
  13. }
复制代码

测试

测试是确保应用质量和稳定性的重要环节。React应用通常使用Jest和React Testing Library进行测试。

Create React App已经内置了Jest和React Testing Library,所以不需要额外安装。如果你使用其他构建工具,可以手动安装:
  1. npm install --save-dev jest @testing-library/react @testing-library/jest-dom
复制代码
  1. // Button.js
  2. import React from 'react';
  3. function Button({ onClick, children }) {
  4.   return (
  5.     <button onClick={onClick}>
  6.       {children}
  7.     </button>
  8.   );
  9. }
  10. export default Button;
复制代码
  1. // Button.test.js
  2. import React from 'react';
  3. import { render, screen, fireEvent } from '@testing-library/react';
  4. import Button from './Button';
  5. test('renders button with text', () => {
  6.   render(<Button>Click Me</Button>);
  7.   const buttonElement = screen.getByText(/Click Me/i);
  8.   expect(buttonElement).toBeInTheDocument();
  9. });
  10. test('calls onClick when button is clicked', () => {
  11.   const handleClick = jest.fn();
  12.   render(<Button onClick={handleClick}>Click Me</Button>);
  13.   
  14.   const buttonElement = screen.getByText(/Click Me/i);
  15.   fireEvent.click(buttonElement);
  16.   
  17.   expect(handleClick).toHaveBeenCalledTimes(1);
  18. });
复制代码
  1. // UserList.js
  2. import React, { useState, useEffect } from 'react';
  3. import axios from 'axios';
  4. function UserList() {
  5.   const [users, setUsers] = useState([]);
  6.   const [loading, setLoading] = useState(true);
  7.   useEffect(() => {
  8.     axios.get('https://jsonplaceholder.typicode.com/users')
  9.       .then(response => {
  10.         setUsers(response.data);
  11.         setLoading(false);
  12.       });
  13.   }, []);
  14.   if (loading) return <div>Loading...</div>;
  15.   return (
  16.     <div>
  17.       <h1>User List</h1>
  18.       <ul>
  19.         {users.map(user => (
  20.           <li key={user.id}>
  21.             {user.name} - {user.email}
  22.           </li>
  23.         ))}
  24.       </ul>
  25.     </div>
  26.   );
  27. }
  28. export default UserList;
复制代码
  1. // UserList.test.js
  2. import React from 'react';
  3. import { render, screen, waitFor } from '@testing-library/react';
  4. import axios from 'axios';
  5. import UserList from './UserList';
  6. // Mock axios
  7. jest.mock('axios');
  8. test('renders user list after loading', async () => {
  9.   // Mock API response
  10.   const mockUsers = [
  11.     { id: 1, name: 'John Doe', email: 'john@example.com' },
  12.     { id: 2, name: 'Jane Smith', email: 'jane@example.com' }
  13.   ];
  14.   
  15.   axios.get.mockResolvedValue({ data: mockUsers });
  16.   
  17.   render(<UserList />);
  18.   
  19.   // Initially should show loading
  20.   expect(screen.getByText(/Loading.../i)).toBeInTheDocument();
  21.   
  22.   // Wait for the user list to be rendered
  23.   await waitFor(() => {
  24.     expect(screen.getByText(/John Doe/i)).toBeInTheDocument();
  25.     expect(screen.getByText(/jane@example.com/i)).toBeInTheDocument();
  26.   });
  27. });
复制代码
  1. // useCounter.js
  2. import { useState } from 'react';
  3. function useCounter(initialValue = 0) {
  4.   const [count, setCount] = useState(initialValue);
  5.   
  6.   const increment = () => setCount(count + 1);
  7.   const decrement = () => setCount(count - 1);
  8.   const reset = () => setCount(initialValue);
  9.   
  10.   return { count, increment, decrement, reset };
  11. }
  12. export default useCounter;
复制代码
  1. // useCounter.test.js
  2. import { renderHook, act } from '@testing-library/react-hooks';
  3. import useCounter from './useCounter';
  4. test('should increment counter', () => {
  5.   const { result } = renderHook(() => useCounter());
  6.   
  7.   act(() => {
  8.     result.current.increment();
  9.   });
  10.   
  11.   expect(result.current.count).toBe(1);
  12. });
  13. test('should decrement counter', () => {
  14.   const { result } = renderHook(() => useCounter());
  15.   
  16.   act(() => {
  17.     result.current.decrement();
  18.   });
  19.   
  20.   expect(result.current.count).toBe(-1);
  21. });
  22. test('should reset counter', () => {
  23.   const { result } = renderHook(() => useCounter(5));
  24.   
  25.   act(() => {
  26.     result.current.increment();
  27.     result.current.increment();
  28.   });
  29.   
  30.   expect(result.current.count).toBe(7);
  31.   
  32.   act(() => {
  33.     result.current.reset();
  34.   });
  35.   
  36.   expect(result.current.count).toBe(5);
  37. });
复制代码

性能优化

随着应用规模的增长,性能优化变得越来越重要。React提供了多种优化技术来提高应用的性能。

React.memo是一个高阶组件,它通过记忆化组件的渲染结果来优化性能。如果组件的props没有变化,React将跳过渲染组件并复用上次渲染的结果。
  1. import React from 'react';
  2. // 普通组件
  3. const ExpensiveComponent = ({ data }) => {
  4.   console.log('ExpensiveComponent rendered');
  5.   return (
  6.     <div>
  7.       {data.map(item => (
  8.         <div key={item.id}>{item.name}</div>
  9.       ))}
  10.     </div>
  11.   );
  12. };
  13. // 使用React.memo优化
  14. const MemoizedExpensiveComponent = React.memo(({ data }) => {
  15.   console.log('MemoizedExpensiveComponent rendered');
  16.   return (
  17.     <div>
  18.       {data.map(item => (
  19.         <div key={item.id}>{item.name}</div>
  20.       ))}
  21.     </div>
  22.   );
  23. });
  24. function App() {
  25.   const [count, setCount] = React.useState(0);
  26.   const [data, setData] = React.useState([
  27.     { id: 1, name: 'Item 1' },
  28.     { id: 2, name: 'Item 2' },
  29.     { id: 3, name: 'Item 3' }
  30.   ]);
  31.   return (
  32.     <div>
  33.       <h1>Count: {count}</h1>
  34.       <button onClick={() => setCount(count + 1)}>Increment</button>
  35.       
  36.       <h2>Expensive Component</h2>
  37.       <ExpensiveComponent data={data} />
  38.       
  39.       <h2>Memoized Expensive Component</h2>
  40.       <MemoizedExpensiveComponent data={data} />
  41.     </div>
  42.   );
  43. }
复制代码

useMemo用于缓存计算结果,避免在每次渲染时都进行昂贵的计算。
  1. import React from 'react';
  2. function ExpensiveCalculation({ numbers }) {
  3.   // 没有使用useMemo,每次渲染都会重新计算
  4.   const sumWithoutMemo = numbers.reduce((acc, num) => acc + num, 0);
  5.   
  6.   // 使用useMemo,只有numbers变化时才重新计算
  7.   const sumWithMemo = React.useMemo(() => {
  8.     console.log('Expensive calculation performed');
  9.     return numbers.reduce((acc, num) => acc + num, 0);
  10.   }, [numbers]);
  11.   return (
  12.     <div>
  13.       <p>Sum without memo: {sumWithoutMemo}</p>
  14.       <p>Sum with memo: {sumWithMemo}</p>
  15.     </div>
  16.   );
  17. }
  18. function App() {
  19.   const [count, setCount] = React.useState(0);
  20.   const [numbers, setNumbers] = React.useState([1, 2, 3, 4, 5]);
  21.   return (
  22.     <div>
  23.       <h1>Count: {count}</h1>
  24.       <button onClick={() => setCount(count + 1)}>Increment</button>
  25.       
  26.       <ExpensiveCalculation numbers={numbers} />
  27.       
  28.       <button onClick={() => setNumbers([...numbers, numbers.length + 1])}>
  29.         Add Number
  30.       </button>
  31.     </div>
  32.   );
  33. }
复制代码

useCallback用于缓存函数,避免在每次渲染时都创建新的函数实例。这在将函数作为props传递给优化过的子组件时特别有用。
  1. import React from 'react';
  2. // 使用React.memo优化的按钮组件
  3. const Button = React.memo(({ onClick, children }) => {
  4.   console.log(`Button "${children}" rendered`);
  5.   return <button onClick={onClick}>{children}</button>;
  6. });
  7. function App() {
  8.   const [count, setCount] = React.useState(0);
  9.   
  10.   // 没有使用useCallback,每次渲染都会创建新的函数
  11.   const incrementWithoutCallback = () => {
  12.     setCount(count + 1);
  13.   };
  14.   
  15.   // 使用useCallback,只有依赖变化时才创建新函数
  16.   const incrementWithCallback = React.useCallback(() => {
  17.     setCount(count + 1);
  18.   }, [count]);
  19.   return (
  20.     <div>
  21.       <h1>Count: {count}</h1>
  22.       
  23.       <Button onClick={incrementWithoutCallback}>
  24.         Increment without useCallback
  25.       </Button>
  26.       
  27.       <Button onClick={incrementWithCallback}>
  28.         Increment with useCallback
  29.       </Button>
  30.     </div>
  31.   );
  32. }
复制代码

代码分割允许你将应用分割成多个包,按需加载,减少初始加载时间。
  1. import React, { Suspense } from 'react';
  2. // 使用React.lazy懒加载组件
  3. const LazyComponent = React.lazy(() => import('./LazyComponent'));
  4. function App() {
  5.   return (
  6.     <div>
  7.       <h1>My App</h1>
  8.       
  9.       {/* 使用Suspense包裹懒加载的组件 */}
  10.       <Suspense fallback={<div>Loading...</div>}>
  11.         <LazyComponent />
  12.       </Suspense>
  13.     </div>
  14.   );
  15. }
复制代码
  1. import React, { Suspense } from 'react';
  2. import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom';
  3. // 懒加载页面组件
  4. const Home = React.lazy(() => import('./Home'));
  5. const About = React.lazy(() => import('./About'));
  6. const Contact = React.lazy(() => import('./Contact'));
  7. function App() {
  8.   return (
  9.     <Router>
  10.       <div>
  11.         <nav>
  12.           <ul>
  13.             <li><Link to="/">Home</Link></li>
  14.             <li><Link to="/about">About</Link></li>
  15.             <li><Link to="/contact">Contact</Link></li>
  16.           </ul>
  17.         </nav>
  18.         <Suspense fallback={<div>Loading...</div>}>
  19.           <Routes>
  20.             <Route path="/" element={<Home />} />
  21.             <Route path="/about" element={<About />} />
  22.             <Route path="/contact" element={<Contact />} />
  23.           </Routes>
  24.         </Suspense>
  25.       </div>
  26.     </Router>
  27.   );
  28. }
复制代码

对于包含大量数据的列表,可以使用虚拟化技术只渲染可见区域的元素,提高性能。
  1. npm install react-window
复制代码
  1. import React from 'react';
  2. import { FixedSizeList as List } from 'react-window';
  3. // 生成大量数据
  4. const generateItems = (count) => {
  5.   return Array.from({ length: count }, (_, index) => ({
  6.     id: index,
  7.     name: `Item ${index + 1}`,
  8.     description: `Description for item ${index + 1}`
  9.   }));
  10. };
  11. const items = generateItems(10000);
  12. // 行组件
  13. const Row = ({ index, style }) => (
  14.   <div style={style} className={index % 2 ? 'ListItemOdd' : 'ListItemEven'}>
  15.     <h3>{items[index].name}</h3>
  16.     <p>{items[index].description}</p>
  17.   </div>
  18. );
  19. function VirtualizedList() {
  20.   return (
  21.     <div>
  22.       <h1>Virtualized List</h1>
  23.       <List
  24.         height={500}
  25.         itemCount={items.length}
  26.         itemSize={100}
  27.         width="100%"
  28.       >
  29.         {Row}
  30.       </List>
  31.     </div>
  32.   );
  33. }
复制代码

部署

开发完成后,需要将React应用部署到服务器上,使其可以通过互联网访问。

使用Create React App创建的项目,可以通过以下命令构建生产版本:
  1. npm run build
复制代码

这将在项目根目录下创建一个build文件夹,包含优化后的生产版本代码。

1. 将构建后的build文件夹上传到GitHub仓库。
2. 登录Netlify,点击”New site from Git”。
3. 选择你的GitHub仓库。
4. 构建设置:Build command:npm run buildPublish directory:build
5. Build command:npm run build
6. Publish directory:build
7. 点击”Deploy site”。

• Build command:npm run build
• Publish directory:build

1. 将构建后的build文件夹上传到GitHub仓库。
2. 登录Vercel,点击”New Project”。
3. 选择你的GitHub仓库。
4. 构建设置:Build command:npm run buildOutput directory:build
5. Build command:npm run build
6. Output directory:build
7. 点击”Deploy”。

• Build command:npm run build
• Output directory:build

1. 安装gh-pages包:
  1. npm install gh-pages --save-dev
复制代码

1. 在package.json中添加部署脚本:
  1. "scripts": {
  2.   "predeploy": "npm run build",
  3.   "deploy": "gh-pages -d build"
  4. }
复制代码

1. 添加homepage字段到package.json:
  1. "homepage": "https://yourusername.github.io/your-repo-name"
复制代码

1. 运行部署命令:
  1. npm run deploy
复制代码

如果你需要将React应用作为Node.js应用的一部分部署,可以使用Express服务器:
  1. // server.js
  2. const express = require('express');
  3. const path = require('path');
  4. const app = express();
  5. // 静态文件服务
  6. app.use(express.static(path.join(__dirname, 'build')));
  7. // 所有路由都返回index.html
  8. app.get('*', (req, res) => {
  9.   res.sendFile(path.join(__dirname, 'build', 'index.html'));
  10. });
  11. const port = process.env.PORT || 3000;
  12. app.listen(port, () => {
  13.   console.log(`Server is running on port ${port}`);
  14. });
复制代码
  1. // package.json
  2. {
  3.   "name": "my-react-app",
  4.   "version": "1.0.0",
  5.   "scripts": {
  6.     "start": "node server.js",
  7.     "build": "react-scripts build",
  8.     "test": "react-scripts test",
  9.     "eject": "react-scripts eject"
  10.   },
  11.   "dependencies": {
  12.     "express": "^4.17.1"
  13.   },
  14.   "devDependencies": {
  15.     "react-scripts": "4.0.3"
  16.   }
  17. }
复制代码

创建Dockerfile:
  1. # 构建阶段
  2. FROM node:16 as build
  3. WORKDIR /app
  4. COPY package*.json ./
  5. RUN npm install
  6. COPY . .
  7. RUN npm run build
  8. # 生产阶段
  9. FROM nginx:alpine
  10. COPY --from=build /app/build /usr/share/nginx/html
  11. EXPOSE 80
  12. CMD ["nginx", "-g", "daemon off;"]
复制代码

构建Docker镜像:
  1. docker build -t my-react-app .
复制代码

运行Docker容器:
  1. docker run -p 80:80 my-react-app
复制代码

最佳实践与常见陷阱

1. 组件设计保持组件小而专注,每个组件只做一件事将UI组件和容器组件分离使用函数组件和Hooks,除非必须使用类组件
2. 保持组件小而专注,每个组件只做一件事
3. 将UI组件和容器组件分离
4. 使用函数组件和Hooks,除非必须使用类组件
5. 状态管理将状态放在最近的共同祖先组件中对于复杂应用,使用Redux或Context API进行全局状态管理避免不必要的状态提升
6. 将状态放在最近的共同祖先组件中
7. 对于复杂应用,使用Redux或Context API进行全局状态管理
8. 避免不必要的状态提升
9. 性能优化使用React.memo、useMemo和useCallback优化性能对大型列表使用虚拟化使用代码分割减少初始加载时间
10. 使用React.memo、useMemo和useCallback优化性能
11. 对大型列表使用虚拟化
12. 使用代码分割减少初始加载时间
13. 代码组织按功能或路由组织文件,而不是按类型使用绝对路径导入保持一致的命名约定
14. 按功能或路由组织文件,而不是按类型
15. 使用绝对路径导入
16. 保持一致的命名约定
17. 测试为组件编写单元测试和集成测试测试用户交互,而不是实现细节使用React Testing Library进行测试
18. 为组件编写单元测试和集成测试
19. 测试用户交互,而不是实现细节
20. 使用React Testing Library进行测试

组件设计

• 保持组件小而专注,每个组件只做一件事
• 将UI组件和容器组件分离
• 使用函数组件和Hooks,除非必须使用类组件

状态管理

• 将状态放在最近的共同祖先组件中
• 对于复杂应用,使用Redux或Context API进行全局状态管理
• 避免不必要的状态提升

性能优化

• 使用React.memo、useMemo和useCallback优化性能
• 对大型列表使用虚拟化
• 使用代码分割减少初始加载时间

代码组织

• 按功能或路由组织文件,而不是按类型
• 使用绝对路径导入
• 保持一致的命名约定

测试

• 为组件编写单元测试和集成测试
• 测试用户交互,而不是实现细节
• 使用React Testing Library进行测试

1.
  1. 直接修改状态“`jsx
  2. // 错误
  3. this.state.count = 1;
复制代码

// 正确
   this.setState({ count: 1 });

// 函数组件中
   // 错误
   const [count, setCount] = useState(0);
   count = 1;

// 正确
   setCount(1);
  1. 2. **在条件语句中使用Hooks**
  2.    ```jsx
  3.    // 错误
  4.    if (condition) {
  5.      const [state, setState] = useState(0);
  6.    }
  7.    
  8.    // 正确
  9.    const [state, setState] = useState(0);
  10.    if (condition) {
  11.      // 使用state
  12.    }
复制代码

1.
  1. 在循环中创建组件“`jsx
  2. // 错误
  3. function List({ items }) {
  4. return ({items.map(item => {
  5.        const [value, setValue] = useState(0);
  6.        return ({item.name}: {value}setValue(value + 1)}>Increment);
  7.      })});
  8. }
复制代码

// 正确 - 提取为单独的组件
   function ListItem({ item }) {
  1. const [value, setValue] = useState(0);
  2. return (
  3.    <div>
  4.      {item.name}: {value}
  5.      <button onClick={() => setValue(value + 1)}>Increment</button>
  6.    </div>
  7. );
复制代码

}

function List({ items }) {
  1. return (
  2.    <div>
  3.      {items.map(item => (
  4.        <ListItem key={item.id} item={item} />
  5.      ))}
  6.    </div>
  7. );
复制代码

}
  1. 4. **过度使用状态**
  2.    ```jsx
  3.    // 错误 - 不必要的状态
  4.    function UserProfile({ user }) {
  5.      const [name, setName] = useState(user.name);
  6.      const [email, setEmail] = useState(user.email);
  7.      
  8.      return (
  9.        <div>
  10.          <h1>{name}</h1>
  11.          <p>{email}</p>
  12.        </div>
  13.      );
  14.    }
  15.    
  16.    // 正确 - 直接使用props
  17.    function UserProfile({ user }) {
  18.      return (
  19.        <div>
  20.          <h1>{user.name}</h1>
  21.          <p>{user.email}</p>
  22.        </div>
  23.      );
  24.    }
复制代码

1.
  1. 忘记依赖数组“`jsx
  2. // 错误 - 缺少依赖
  3. useEffect(() => {
  4. const timer = setInterval(() => {
  5.    setCount(count + 1);
  6. }, 1000);return () => clearInterval(timer);
  7. }, []); // 缺少count依赖
复制代码

忘记依赖数组“`jsx
// 错误 - 缺少依赖
useEffect(() => {
const timer = setInterval(() => {
   setCount(count + 1);
}, 1000);

return () => clearInterval(timer);
}, []); // 缺少count依赖

// 正确 - 包含所有依赖
   useEffect(() => {
  1. const timer = setInterval(() => {
  2.    setCount(count + 1);
  3. }, 1000);
  4. return () => clearInterval(timer);
复制代码

}, [count]); // 包含count依赖

// 或者使用函数式更新避免依赖
   useEffect(() => {
  1. const timer = setInterval(() => {
  2.    setCount(prevCount => prevCount + 1);
  3. }, 1000);
  4. return () => clearInterval(timer);
复制代码

}, []); // 不需要依赖
   “`

总结与展望

React作为一个强大的前端框架,已经发展多年并持续演进。从最初的类组件到现在的函数组件和Hooks,React不断提供更好的开发体验和性能优化。

本教程涵盖了React的核心概念、实际应用和最佳实践,包括:

• JSX语法和组件概念
• Props和State管理
• 生命周期和Hooks
• 路由与导航
• 状态管理(Redux、MobX)
• 与后端交互
• 样式处理
• 测试
• 性能优化
• 部署
• 最佳实践与常见陷阱

随着React生态系统的发展,我们可以期待更多创新和改进。React 18已经引入了并发渲染、自动批处理、Suspense等新特性,这些将进一步改善用户体验和开发体验。

要成为一名优秀的React开发者,除了掌握框架本身,还需要了解JavaScript的最新特性、Web API、性能优化技巧以及整个前端生态系统。持续学习和实践是关键。

希望本教程能够帮助你入门React开发,并在你的项目中应用这些知识。祝你编码愉快!
「七転び八起き(ななころびやおき)」
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则