React 中文教程

1. 项目概述

React 是由 Facebook 开发的用于构建用户界面的 JavaScript 库,它采用组件化的开发方式,使得构建复杂的用户界面变得更加简单和可维护。

1.1 主要功能

  • 组件化开发:将 UI 拆分为独立、可复用的组件
  • 虚拟 DOM:通过虚拟 DOM 提高渲染性能
  • 单向数据流:数据流向清晰,便于调试和维护
  • JSX 语法:在 JavaScript 中编写类似 HTML 的代码,提高开发效率
  • Hooks API:在函数组件中使用状态和其他 React 特性
  • 服务端渲染:支持在服务器端渲染 React 组件,提高首屏加载速度和 SEO

1.2 技术栈特点

  • 声明式编程:只需描述 UI 的最终状态,React 会处理如何更新 DOM
  • 高效渲染:通过虚拟 DOM 和 diff 算法,只更新需要变化的部分
  • 生态系统丰富:拥有大量的第三方库和工具
  • 跨平台:除了 Web 浏览器,还可以用于开发移动应用(React Native)和桌面应用
  • 强大的社区支持:作为前端开发的主流框架之一,拥有庞大的社区和丰富的学习资源

1.3 GitHub Stars

220k+

2. 安装设置

2.1 使用 Create React App

Create React App 是 React 官方推荐的项目脚手架工具,它会自动配置好开发环境,让你可以专注于编写代码。

# 安装 Create React App
npm install -g create-react-app

# 创建新的 React 项目
npx create-react-app my-app

# 进入项目目录
cd my-app

# 启动开发服务器
npm start

2.2 使用 Vite

Vite 是一个现代化的前端构建工具,它提供了更快的开发体验。

# 使用 npm
npm create vite@latest my-app -- --template react

# 使用 yarn
yarn create vite my-app --template react

# 使用 pnpm
pnpm create vite my-app --template react

# 进入项目目录
cd my-app

# 安装依赖
npm install

# 启动开发服务器
npm run dev

2.3 手动配置

如果你需要更灵活的配置,可以手动设置 React 项目。

# 创建项目目录
mkdir my-app
cd my-app

# 初始化 package.json
npm init -y

# 安装 React 和 React DOM
npm install react react-dom

# 安装构建工具
npm install --save-dev webpack webpack-cli webpack-dev-server babel-loader @babel/core @babel/preset-react

# 创建 .babelrc 文件
{
  "presets": ["@babel/preset-react"]
}

# 创建 webpack.config.js 文件
const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js'
  },
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        exclude: /node_modules/,
        use: 'babel-loader'
      }
    ]
  },
  devServer: {
    contentBase: path.resolve(__dirname, 'public'),
    port: 3000
  }
};

# 创建 src/index.js 文件
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

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

# 创建 src/App.js 文件
import React from 'react';

function App() {
  return (
    <div className="App">
      <h1>Hello React!</h1>
    </div>
  );
}

export default App;

# 创建 public/index.html 文件
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>React App</title>
</head>
<body>
  <div id="root"></div>
  <script src="../dist/bundle.js"></script>
</body>
</html>

3. 基本使用

3.1 组件定义

React 组件可以通过函数或类来定义。

3.1.1 函数组件

import React from 'react';

function Greeting(props) {
  return <h1>Hello, {props.name}!</h1>;
}

export default Greeting;

3.1.2 类组件

import React, { Component } from 'react';

class Greeting extends Component {
  render() {
    return <h1>Hello, {this.props.name}!</h1>;
  }
}

export default Greeting;

3.2 状态管理

在 React 中,可以使用 useState Hook 或类组件的 this.state 来管理组件状态。

3.2.1 使用 useState Hook

import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

export default Counter;

3.2.2 使用类组件的状态

import React, { Component } from 'react';

class Counter extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  incrementCount() {
    this.setState(prevState => ({
      count: prevState.count + 1
    }));
  }

  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={() => this.incrementCount()}>
          Click me
        </button>
      </div>
    );
  }
}

export default Counter;

3.3 生命周期

在函数组件中,可以使用 useEffect Hook 来处理副作用和模拟生命周期方法。在类组件中,可以使用生命周期方法。

3.3.1 使用 useEffect Hook

import React, { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  // 相当于 componentDidMount 和 componentDidUpdate
  useEffect(() => {
    // 更新文档标题
    document.title = `You clicked ${count} times`;

    // 清理函数,相当于 componentWillUnmount
    return () => {
      // 执行清理操作
    };
  }, [count]); // 只有当 count 变化时才会重新运行

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

export default Example;

3.3.2 使用类组件的生命周期方法

import React, { Component } from 'react';

class Example extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  componentDidMount() {
    // 组件挂载后执行
    document.title = `You clicked ${this.state.count} times`;
  }

  componentDidUpdate(prevProps, prevState) {
    // 组件更新后执行
    if (prevState.count !== this.state.count) {
      document.title = `You clicked ${this.state.count} times`;
    }
  }

  componentWillUnmount() {
    // 组件卸载前执行
    // 执行清理操作
  }

  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>
    );
  }
}

export default Example;

3.4 事件处理

React 中的事件处理与 DOM 事件类似,但有一些语法差异。

import React, { useState } from 'react';

function Toggle() {
  const [isToggleOn, setIsToggleOn] = useState(true);

  function handleClick() {
    setIsToggleOn(prevState => !prevState);
  }

  return (
    <button onClick={handleClick}>
      {isToggleOn ? 'ON' : 'OFF'}
    </button>
  );
}

export default Toggle;

3.5 条件渲染

React 支持条件渲染,可以根据条件显示不同的内容。

import React, { useState } from 'react';

function Greeting() {
  const [isLoggedIn, setIsLoggedIn] = useState(false);

  return (
    <div>
      {isLoggedIn ? (
        <button onClick={() => setIsLoggedIn(false)}>Logout</button>
      ) : (
        <button onClick={() => setIsLoggedIn(true)}>Login</button>
      )}
    </div>
  );
}

export default Greeting;

3.6 列表渲染

可以使用 map 方法来渲染列表。

import React from 'react';

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    <li key={number.toString()}>
      {number}
    </li>
  );
  return (
    <ul>{listItems}</ul>
  );
}

export default NumberList;

4. 高级功能

4.1 上下文(Context)

Context 提供了一种在组件树中共享值的方式,而不必显式地通过 props 传递。

import React, { createContext, useContext, useState } from 'react';

// 创建 Context
const ThemeContext = createContext();

// 创建 Provider 组件
function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light');

  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}

// 创建使用 Context 的 Hook
function useTheme() {
  return useContext(ThemeContext);
}

// 使用 Context 的组件
function ThemedButton() {
  const { theme, setTheme } = useTheme();

  return (
    <button
      onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}
      style={{
        background: theme === 'light' ? '#fff' : '#333',
        color: theme === 'light' ? '#333' : '#fff'
      }}
    >
      Toggle {theme === 'light' ? 'Dark' : 'Light'} Mode
    </button>
  );
}

// 应用组件
function App() {
  return (
    <ThemeProvider>
      <ThemedButton />
    </ThemeProvider>
  );
}

export default App;

4.2 引用(Refs)

Refs 提供了一种方式来访问 DOM 节点或在 render 方法中创建的 React 元素。

import React, { useRef, useEffect } from 'react';

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

  useEffect(() => {
    // 组件挂载后聚焦输入框
    inputRef.current.focus();
  }, []);

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

export default FocusInput;

4.3 性能优化

4.3.1 使用 React.memo

React.memo 可以缓存组件的渲染结果,避免不必要的重新渲染。

import React, { useState, memo } from 'react';

// 使用 memo 包装组件
const ExpensiveComponent = memo(({ value }) => {
  console.log('Rendering ExpensiveComponent');
  // 模拟昂贵的计算
  for (let i = 0; i < 1000000000; i++) {
    // 空循环
  }
  return <div>Value: {value}</div>;
});

function App() {
  const [count, setCount] = useState(0);
  const [value, setValue] = useState(0);

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>
        Increment Count: {count}
      </button>
      <button onClick={() => setValue(value + 1)}>
        Increment Value: {value}
      </button>
      <ExpensiveComponent value={value} />
    </div>
  );
}

export default App;

4.3.2 使用 useCallback 和 useMemo

useCallback 可以缓存函数引用,useMemo 可以缓存计算结果。

import React, { useState, useCallback, useMemo } from 'react';

function App() {
  const [count, setCount] = useState(0);
  const [todos, setTodos] = useState([]);

  // 使用 useCallback 缓存函数
  const addTodo = useCallback(() => {
    setTodos(prevTodos => [...prevTodos, `Todo ${prevTodos.length + 1}`]);
  }, []);

  // 使用 useMemo 缓存计算结果
  const sortedTodos = useMemo(() => {
    return todos.sort();
  }, [todos]);

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>
        Count: {count}
      </button>
      <button onClick={addTodo}>
        Add Todo
      </button>
      <ul>
        {sortedTodos.map((todo, index) => (
          <li key={index}>{todo}</li>
        ))}
      </ul>
    </div>
  );
}

export default App;

4.4 错误边界

错误边界可以捕获其子组件树中的 JavaScript 错误,并显示备用 UI,而不是整个组件树崩溃。

import React, { Component } from 'react';

class ErrorBoundary extends Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false, error: null };
  }

  static getDerivedStateFromError(error) {
    // 更新状态,下次渲染时显示备用 UI
    return { hasError: true, error };
  }

  componentDidCatch(error, errorInfo) {
    // 可以在这里记录错误信息
    console.error('Error caught by ErrorBoundary:', error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      // 显示备用 UI
      return <h1>Something went wrong: {this.state.error.message}</h1>;
    }

    // 正常渲染子组件
    return this.props.children;
  }
}

export default ErrorBoundary;

4.5 自定义 Hooks

可以创建自定义 Hooks 来复用状态逻辑。

import React, { useState, useEffect } from 'react';

// 创建自定义 Hook
function useCounter(initialValue = 0) {
  const [count, setCount] = useState(initialValue);

  const increment = () => setCount(count + 1);
  const decrement = () => setCount(count - 1);
  const reset = () => setCount(initialValue);

  return { count, increment, decrement, reset };
}

// 使用自定义 Hook
function Counter() {
  const { count, increment, decrement, reset } = useCounter(0);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
      <button onClick={reset}>Reset</button>
    </div>
  );
}

export default Counter;

5. 实际应用场景

5.1 表单处理

import React, { useState } from 'react';

function LoginForm() {
  const [formData, setFormData] = useState({
    username: '',
    password: ''
  });

  const handleChange = (e) => {
    const { name, value } = e.target;
    setFormData(prevData => ({
      ...prevData,
      [name]: value
    }));
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log('Form submitted:', formData);
    // 处理表单提交逻辑
  };

  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label htmlFor="username">Username:</label>
        <input
          type="text"
          id="username"
          name="username"
          value={formData.username}
          onChange={handleChange}
        />
      </div>
      <div>
        <label htmlFor="password">Password:</label>
        <input
          type="password"
          id="password"
          name="password"
          value={formData.password}
          onChange={handleChange}
        />
      </div>
      <button type="submit">Login</button>
    </form>
  );
}

export default LoginForm;

5.2 数据获取

import React, { useState, useEffect } from 'react';

function UserList() {
  const [users, setUsers] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    async function fetchUsers() {
      try {
        const response = await fetch('https://jsonplaceholder.typicode.com/users');
        if (!response.ok) {
          throw new Error('Failed to fetch users');
        }
        const data = await response.json();
        setUsers(data);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    }

    fetchUsers();
  }, []);

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error}</div>;

  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>
          {user.name} ({user.email})
        </li>
      ))}
    </ul>
  );
}

export default UserList;

5.3 路由

使用 React Router 来处理应用的路由。

import React from 'react';
import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom';

function Home() {
  return <h1>Home</h1>;
}

function About() {
  return <h1>About</h1>;
}

function Contact() {
  return <h1>Contact</h1>;
}

function App() {
  return (
    <Router>
      <div>
        <nav>
          <ul>
            <li>
              <Link to="/">Home</Link>
            </li>
            <li>
              <Link to="/about">About</Link>
            </li>
            <li>
              <Link to="/contact">Contact</Link>
            </li>
          </ul>
        </nav>

        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/about" element={<About />} />
          <Route path="/contact" element={<Contact />} />
        </Routes>
      </div>
    </Router>
  );
}

export default App;

6. 代码优化建议

6.1 使用函数组件和 Hooks

函数组件和 Hooks 是 React 的现代特性,它们提供了更简洁、更灵活的方式来编写 React 代码。

6.2 合理使用 memo、useCallback 和 useMemo

这些优化手段可以减少不必要的渲染,提高应用性能,但不要过度使用,以免增加代码复杂度。

6.3 拆分组件

将大型组件拆分为更小、更专注的组件,提高代码的可维护性和可测试性。

6.4 使用 PropTypes 或 TypeScript

使用 PropTypes 或 TypeScript 来类型检查组件的 props,减少运行时错误。

6.5 避免在 render 方法中创建新函数

在 render 方法中创建新函数会导致每次渲染时都创建新的函数实例,影响性能。可以使用 useCallback 或在组件外部定义函数。

6.6 合理使用状态

将状态放在最合适的组件中,避免状态提升过高或过低。

6.7 使用正确的 key

在渲染列表时,使用唯一且稳定的 key,避免使用索引作为 key(除非列表是静态的)。

6.8 优化条件渲染

对于频繁切换的条件渲染,可以使用 React.memo 来缓存组件。

6.9 使用懒加载

对于大型应用,可以使用 React.lazy 和 Suspense 来实现组件的懒加载,减少初始包大小。

6.10 合理使用 Context

Context 适合共享那些被多个组件需要的值,避免过度使用 Context,以免导致不必要的渲染。

7. 参考资源

8. 总结

React 是一个功能强大、灵活且高效的前端框架,它通过组件化开发、虚拟 DOM、单向数据流等特性,使得构建复杂的用户界面变得更加简单和可维护。

通过本教程的学习,你应该已经掌握了 React 的核心概念和基本使用方法,包括组件定义、状态管理、生命周期、事件处理、条件渲染、列表渲染等。同时,你也了解了 React 的一些高级特性,如 Context、Refs、性能优化、错误边界和自定义 Hooks 等。

React 的生态系统非常丰富,有许多优秀的第三方库和工具,如 React Router、Redux、Material-UI 等,它们可以帮助你更高效地开发 React 应用。

作为前端开发的主流框架之一,React 拥有庞大的社区和丰富的学习资源,如果你在学习或开发过程中遇到问题,可以通过官方文档、社区论坛、GitHub 等渠道寻求帮助。

希望本教程对你有所帮助,祝你在 React 开发之路上取得成功!

« 上一篇 officegen 中文教程 下一篇 » Vue.js 教程 - 渐进式 JavaScript 框架