前端开发

React 完全教程

从零开始学习 React,掌握现代前端开发的核心技能

React 完全教程

React 是由 Facebook 开发的用于构建用户界面的 JavaScript 库。它采用组件化的开发方式,让构建复杂的 UI 变得简单高效。

为什么选择 React?

  • 组件化:将 UI 拆分成独立、可复用的组件
  • 声明式:描述 UI 应该是什么样子,React 负责更新
  • 虚拟 DOM:高效的 DOM 更新机制
  • 生态丰富:庞大的社区和丰富的第三方库
  • 跨平台:React Native 支持移动端开发

环境搭建

使用 Vite 创建项目

npm create vite@latest my-react-app -- --template react-ts
cd my-react-app
npm install
npm run dev

使用 Next.js(推荐)

npx create-next-app@latest my-app
cd my-app
npm run dev

核心概念

1. JSX

JSX 是 JavaScript 的语法扩展,让你可以在 JavaScript 中编写类似 HTML 的代码。

function Welcome() {
  const name = "World";
  return (
    <div>
      <h1>Hello, {name}!</h1>
      <p>Welcome to React</p>
    </div>
  );
}

JSX 规则

  • 必须返回单个根元素(或使用 Fragment <>...</>
  • 所有标签必须闭合
  • 使用 className 代替 class
  • 使用 {} 嵌入 JavaScript 表达式

2. 组件

组件是 React 的核心概念,有两种定义方式:

函数组件(推荐):

function Button({ text, onClick }) {
  return (
    <button onClick={onClick}>
      {text}
    </button>
  );
}

类组件(传统方式):

class Button extends React.Component {
  render() {
    return (
      <button onClick={this.props.onClick}>
        {this.props.text}
      </button>
    );
  }
}

3. Props

Props 是组件的输入,用于父组件向子组件传递数据。

function UserCard({ name, email, avatar }) {
  return (
    <div className="user-card">
      <img src={avatar} alt={name} />
      <h3>{name}</h3>
      <p>{email}</p>
    </div>
  );
}

// 使用组件
<UserCard
  name="张三"
  email="zhangsan@example.com"
  avatar="/avatar.jpg"
/>

Props 的特点

  • 只读,不能修改
  • 可以传递任何类型的数据
  • 可以设置默认值
function Button({ text = "点击", variant = "primary" }) {
  return <button className={variant}>{text}</button>;
}

4. State

State 是组件的内部状态,当 state 改变时,组件会重新渲染。

import { useState } from 'react';

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

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>
        增加
      </button>
      <button onClick={() => setCount(count - 1)}>
        减少
      </button>
    </div>
  );
}

React Hooks

Hooks 是 React 16.8 引入的新特性,让函数组件也能使用 state 和其他 React 特性。

useState

管理组件状态。

const [state, setState] = useState(initialValue);

示例

function Form() {
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log({ name, email });
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        value={name}
        onChange={(e) => setName(e.target.value)}
        placeholder="姓名"
      />
      <input
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        placeholder="邮箱"
      />
      <button type="submit">提交</button>
    </form>
  );
}

useEffect

处理副作用(数据获取、订阅、DOM 操作等)。

useEffect(() => {
  // 副作用代码
  return () => {
    // 清理函数(可选)
  };
}, [dependencies]);

示例

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    async function fetchUser() {
      setLoading(true);
      const response = await fetch(`/api/users/${userId}`);
      const data = await response.json();
      setUser(data);
      setLoading(false);
    }

    fetchUser();
  }, [userId]); // 当 userId 改变时重新执行

  if (loading) return <div>加载中...</div>;
  if (!user) return <div>用户不存在</div>;

  return (
    <div>
      <h2>{user.name}</h2>
      <p>{user.email}</p>
    </div>
  );
}

useContext

跨组件共享数据,避免 props 层层传递。

import { 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
function ThemedButton() {
  const { theme, setTheme } = useContext(ThemeContext);

  return (
    <button
      className={theme}
      onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}
    >
      切换主题
    </button>
  );
}

useRef

访问 DOM 元素或保存可变值。

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

  const focusInput = () => {
    inputRef.current.focus();
  };

  return (
    <div>
      <input ref={inputRef} type="text" />
      <button onClick={focusInput}>聚焦输入框</button>
    </div>
  );
}

useMemo 和 useCallback

性能优化 Hooks。

// useMemo:缓存计算结果
const expensiveValue = useMemo(() => {
  return computeExpensiveValue(a, b);
}, [a, b]);

// useCallback:缓存函数
const handleClick = useCallback(() => {
  console.log('clicked');
}, []);

自定义 Hook

封装可复用的逻辑。

function useLocalStorage(key, initialValue) {
  const [value, setValue] = useState(() => {
    const stored = localStorage.getItem(key);
    return stored ? JSON.parse(stored) : initialValue;
  });

  useEffect(() => {
    localStorage.setItem(key, JSON.stringify(value));
  }, [key, value]);

  return [value, setValue];
}

// 使用
function App() {
  const [name, setName] = useLocalStorage('name', '');

  return (
    <input
      value={name}
      onChange={(e) => setName(e.target.value)}
    />
  );
}

状态管理

Context API

适合中小型应用的状态管理。

// store.js
import { createContext, useContext, useReducer } from 'react';

const StoreContext = createContext();

const initialState = {
  user: null,
  cart: [],
};

function reducer(state, action) {
  switch (action.type) {
    case 'SET_USER':
      return { ...state, user: action.payload };
    case 'ADD_TO_CART':
      return { ...state, cart: [...state.cart, action.payload] };
    default:
      return state;
  }
}

export function StoreProvider({ children }) {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <StoreContext.Provider value={{ state, dispatch }}>
      {children}
    </StoreContext.Provider>
  );
}

export function useStore() {
  return useContext(StoreContext);
}

Zustand(推荐)

轻量级状态管理库。

npm install zustand
import { create } from 'zustand';

const useStore = create((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
  decrement: () => set((state) => ({ count: state.count - 1 })),
}));

function Counter() {
  const { count, increment, decrement } = useStore();

  return (
    <div>
      <p>{count}</p>
      <button onClick={increment}>+</button>
      <button onClick={decrement}>-</button>
    </div>
  );
}

路由

React Router

npm install react-router-dom
import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';

function App() {
  return (
    <BrowserRouter>
      <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/:id" element={<UserDetail />} />
      </Routes>
    </BrowserRouter>
  );
}

数据获取

使用 fetch

function Posts() {
  const [posts, setPosts] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    fetch('/api/posts')
      .then(res => res.json())
      .then(data => {
        setPosts(data);
        setLoading(false);
      })
      .catch(err => {
        setError(err.message);
        setLoading(false);
      });
  }, []);

  if (loading) return <div>加载中...</div>;
  if (error) return <div>错误: {error}</div>;

  return (
    <ul>
      {posts.map(post => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
}

使用 TanStack Query(推荐)

npm install @tanstack/react-query
import { useQuery } from '@tanstack/react-query';

function Posts() {
  const { data, isLoading, error } = useQuery({
    queryKey: ['posts'],
    queryFn: () => fetch('/api/posts').then(res => res.json()),
  });

  if (isLoading) return <div>加载中...</div>;
  if (error) return <div>错误: {error.message}</div>;

  return (
    <ul>
      {data.map(post => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
}

性能优化

1. React.memo

防止不必要的重新渲染。

const ExpensiveComponent = React.memo(function ExpensiveComponent({ data }) {
  // 只有当 data 改变时才重新渲染
  return <div>{/* 复杂的渲染逻辑 */}</div>;
});

2. 代码分割

使用动态导入减少初始加载时间。

import { lazy, Suspense } from 'react';

const HeavyComponent = lazy(() => import('./HeavyComponent'));

function App() {
  return (
    <Suspense fallback={<div>加载中...</div>}>
      <HeavyComponent />
    </Suspense>
  );
}

3. 虚拟化长列表

npm install react-window
import { FixedSizeList } from 'react-window';

function VirtualList({ items }) {
  return (
    <FixedSizeList
      height={600}
      itemCount={items.length}
      itemSize={50}
      width="100%"
    >
      {({ index, style }) => (
        <div style={style}>
          {items[index]}
        </div>
      )}
    </FixedSizeList>
  );
}

最佳实践

1. 组件设计

  • 保持组件小而专注
  • 使用组合而非继承
  • 提取可复用的逻辑到自定义 Hook

2. 状态管理

  • 状态尽可能放在最近的共同父组件
  • 避免不必要的全局状态
  • 使用 Context 或状态管理库管理复杂状态

3. 性能

  • 使用 React DevTools Profiler 分析性能
  • 避免在渲染函数中创建新对象/函数
  • 合理使用 memo、useMemo、useCallback

4. 代码组织

src/
├── components/     # 可复用组件
├── pages/          # 页面组件
├── hooks/          # 自定义 Hooks
├── utils/          # 工具函数
├── services/       # API 调用
├── store/          # 状态管理
└── types/          # TypeScript 类型

常用库推荐

  • UI 组件库:Shadcn UI, Material-UI, Ant Design
  • 状态管理:Zustand, Jotai, Redux Toolkit
  • 数据获取:TanStack Query, SWR
  • 表单:React Hook Form, Formik
  • 动画:Framer Motion, React Spring
  • 图表:Recharts, Chart.js

总结

React 是现代前端开发的核心技能。掌握 React 可以让你:

  • 构建高性能的单页应用
  • 开发可维护的大型项目
  • 使用 React Native 开发移动应用
  • 加入庞大的 React 生态系统

开始你的 React 之旅,构建出色的用户界面!

参考资源