React 完整知识点总结 · AI导师

React 完整知识体系
从入门到精通

全面覆盖 React 18+ 核心技术、最佳实践与高级模式

核心概念 Hooks 系统 状态管理 性能优化 SSR/SSG

React 学习路径图

1

基础阶段 入门

JSX、组件、Props、State、生命周期

2

核心进阶 中级

Hooks、状态管理、Context、错误边界

3

性能优化 高级

渲染优化、虚拟化、代码分割、懒加载

4

生态与架构 专家

Next.js、状态管理方案、测试、部署

学习建议: React 的核心是组件化声明式编程。不要急于学习所有内容,应按顺序掌握每个阶段的核心概念。大多数项目只需要掌握到"核心进阶"阶段。

1. React 基础核心

JSX:JavaScript XML

JSX 是 React 的核心语法扩展,它允许在 JavaScript 中编写类似 HTML 的代码。

JSX 基本语法
// JSX 是语法糖,会被 Babel 编译为 React.createElement()
const element = <h1 className="title">Hello, React!</h1>;

// 编译后:
const element = React.createElement(
  'h1',
  { className: 'title' },
  'Hello, React!'
);

// 表达式嵌入
const name = 'World';
const element = <h1>Hello, {name}</h1>;

// JSX 也是表达式
function getGreeting(user) {
  if (user) {
    return <h1>Hello, {user.name}!</h1>;
  }
  return <h1>Hello, Stranger.</h1>;
}

组件:构建 UI 的基石

函数组件(推荐)

使用函数定义,简洁且支持 Hooks

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

// 或使用箭头函数
const Welcome = (props) => {
  return <h1>Hello, {props.name}</h1>;
};
类组件(传统)

使用 ES6 class 定义,有生命周期

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

Props 与 State

Props:只读属性

父组件传递给子组件的数据

// 传递 Props
<User name="John" age={25} />

// 接收 Props(函数组件)
function User(props) {
  return (
    <div>
      <p>Name: {props.name}</p>
      <p>Age: {props.age}</p>
    </div>
  );
}

// 解构 Props(推荐)
function User({ name, age }) {
  return (
    <div>
      <p>Name: {name}</p>
      <p>Age: {age}</p>
    </div>
  );
}
State:组件内部状态

组件内部可变的数据

// 类组件中使用 state
class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }
  
  increment = () => {
    this.setState({ count: this.state.count + 1 });
  };
  
  render() {
    return (
      <div>
        <p>Count: {this.state.count}</p>
        <button onClick={this.increment}>Increment</button>
      </div>
    );
  }
}

事件处理与条件渲染

事件处理
function Button() {
  const handleClick = (e) => {
    console.log('Clicked!', e);
  };
  
  const handleSubmit = (event) => {
    event.preventDefault(); // 阻止默认行为
    console.log('Form submitted');
  };
  
  return (
    <>
      <button onClick={handleClick}>Click me</button>
      <form onSubmit={handleSubmit}>
        <button type="submit">Submit</button>
      </form>
    </>
  );
}
条件渲染
function UserGreeting({ isLoggedIn }) {
  // 1. if 语句
  if (isLoggedIn) {
    return <h1>Welcome back!</h1>;
  }
  return <h1>Please sign in.</h1>;
  
  // 2. 三元运算符
  return (
    <div>
      {isLoggedIn ? <h1>Welcome back!</h1> : <h1>Please sign in.</h1>}
    </div>
  );
  
  // 3. 逻辑与运算符
  return (
    <div>
      {isLoggedIn && <h1>Welcome back!</h1>}
      {!isLoggedIn && <button>Sign in</button>}
    </div>
  );
}
关键概念: React 的核心是声明式UI 编程。你描述 UI 应该是什么样子(基于当前 state),React 负责更新 DOM 以匹配。这与 jQuery 等命令式库(直接操作 DOM)有根本区别。

2. Hooks 系统(React 16.8+)

为什么需要 Hooks?

简化代码

告别类组件,减少样板代码

逻辑复用

自定义 Hook 共享逻辑

心智模型统一

只有函数,没有 this 绑定问题

基础 Hooks

useState 状态管理

import { useState } from 'react';

function Counter() {
  // 1. 基本用法
  const [count, setCount] = useState(0);
  
  // 2. 函数式更新
  const increment = () => {
    setCount(prevCount => prevCount + 1);
  };
  
  // 3. 复杂状态
  const [user, setUser] = useState({
    name: 'John',
    age: 25,
  });
  
  const updateName = (name) => {
    setUser(prev => ({ ...prev, name }));
  };
  
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>+1</button>
      <button onClick={increment}>函数式更新</button>
    </div>
  );
}

useEffect 副作用处理

import { useState, useEffect } from 'react';

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);
  
  // 1. 组件挂载时执行(componentDidMount)
  useEffect(() => {
    console.log('组件已挂载');
    
    // 清理函数(componentWillUnmount)
    return () => {
      console.log('组件即将卸载');
    };
  }, []);
  
  // 2. 依赖变化时执行(componentDidUpdate)
  useEffect(() => {
    if (!userId) return;
    
    setLoading(true);
    fetchUser(userId).then(data => {
      setUser(data);
      setLoading(false);
    });
    
    // 清理函数:取消请求或清理订阅
    return () => {
      // 取消请求
    };
  }, [userId]); // 依赖数组:userId 变化时重新执行
  
  // 3. 每次渲染后执行
  useEffect(() => {
    console.log('每次渲染后执行');
  }); // 没有依赖数组
  
  if (loading) return <div>Loading...</div>;
  return <div>{user.name}</div>;
}

useContext 跨组件传递

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

// 1. 创建 Context
const ThemeContext = createContext('light');

function App() {
  const [theme, setTheme] = useState('light');
  
  return (
    // 2. 提供 Context 值
    <ThemeContext.Provider value={{ theme, setTheme }}>
      <Toolbar />
    </ThemeContext.Provider>
  );
}

function Toolbar() {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

function ThemedButton() {
  // 3. 使用 Context
  const { theme, setTheme } = useContext(ThemeContext);
  
  return (
    <button
      style={{ background: theme === 'dark' ? '#333' : '#fff' }}
      onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}
    >
      Toggle Theme
    </button>
  );
}

其他基础 Hooks

  • useReducer useState 的替代方案

    复杂状态逻辑,类似 Redux

  • useMemo 记忆计算结果

    避免重复计算,性能优化

  • useCallback 记忆回调函数

    避免子组件不必要渲染

  • useRef 引用 DOM 或值

    访问 DOM 或存储可变值

自定义 Hooks:逻辑复用

// hooks/useLocalStorage.js
import { useState, useEffect } from 'react';

function useLocalStorage(key, initialValue) {
  // 从 localStorage 读取初始值
  const [storedValue, setStoredValue] = useState(() => {
    try {
      const item = window.localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      console.error(error);
      return initialValue;
    }
  });
  
  // 更新 localStorage
  const setValue = (value) => {
    try {
      const valueToStore = value instanceof Function ? value(storedValue) : value;
      setStoredValue(valueToStore);
      window.localStorage.setItem(key, JSON.stringify(valueToStore));
    } catch (error) {
      console.error(error);
    }
  };
  
  return [storedValue, setValue];
}

// hooks/useFetch.js
function useFetch(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  
  useEffect(() => {
    const fetchData = async () => {
      try {
        setLoading(true);
        const response = await fetch(url);
        if (!response.ok) throw new Error('Network response was not ok');
        const result = await response.json();
        setData(result);
      } catch (err) {
        setError(err);
      } finally {
        setLoading(false);
      }
    };
    
    fetchData();
  }, [url]);
  
  return { data, loading, error };
}

// 在组件中使用
function UserProfile() {
  const [theme, setTheme] = useLocalStorage('theme', 'light');
  const { data: user, loading, error } = useFetch('/api/user/1');
  
  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;
  
  return (
    <div className={`theme-${theme}`}>
      <h1>{user.name}</h1>
      <button onClick={() => setTheme('dark')}>Dark Mode</button>
    </div>
  );
}
Hooks 规则: 1. 只在最顶层调用 Hooks(不在循环、条件、嵌套函数中调用)。2. 只在 React 函数组件或自定义 Hook 中调用 Hooks。使用 eslint-plugin-react-hooks 自动检查。

3. 状态管理方案

状态管理演进

方案 适用场景 复杂度 推荐程度
组件状态 单个组件内部状态 优先使用
Context API 主题、用户信息等全局数据 ⭐⭐ 简单应用
Zustand 中小型应用,简单易用 ⭐⭐ 推荐
Redux Toolkit 大型复杂应用,团队协作 ⭐⭐⭐⭐ 大型项目
Recoil / Jotai 原子状态管理,细粒度更新 ⭐⭐⭐ 实验性
重要原则: 不要过度使用全局状态!大部分状态应该是本地状态。只有真正需要在多个不相关组件间共享的状态才应该提升到全局。过早优化是复杂性的根源。

Zustand 现代轻量方案

// store/counterStore.js
import { create } from 'zustand';

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

// 在组件中使用
function Counter() {
  const { count, increment, decrement } = useCounterStore();
  
  return (
    <div>
      <h1>Count: {count}</h1>
      <button onClick={increment}>+</button>
      <button onClick={decrement}>-</button>
    </div>
  );
}

// 异步 action
const useUserStore = create((set) => ({
  users: [],
  loading: false,
  fetchUsers: async () => {
    set({ loading: true });
    const response = await fetch('/api/users');
    const users = await response.json();
    set({ users, loading: false });
  },
}));

// 选择器:避免不必要的重渲染
function UserList() {
  const users = useUserStore((state) => state.users);
  const fetchUsers = useUserStore((state) => state.fetchUsers);
  
  useEffect(() => {
    fetchUsers();
  }, [fetchUsers]);
  
  return (
    <ul>
      {users.map(user => <li key={user.id}>{user.name}</li>)}
    </ul>
  );
}

Redux Toolkit 企业级方案

// store/slices/counterSlice.js
import { 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;
    },
  },
});

// 异步 thunk
export const incrementAsync = (amount) => (dispatch) => {
  setTimeout(() => {
    dispatch(incrementByAmount(amount));
  }, 1000);
};

export const { increment, decrement, incrementByAmount } = counterSlice.actions;
export default counterSlice.reducer;

// store/index.js
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from './slices/counterSlice';

export const store = configureStore({
  reducer: {
    counter: counterReducer,
  },
});

// 在组件中使用
import { useSelector, useDispatch } from 'react-redux';
import { increment, decrement } from './store/slices/counterSlice';

function Counter() {
  const count = useSelector((state) => state.counter.value);
  const dispatch = useDispatch();
  
  return (
    <div>
      <h1>Count: {count}</h1>
      <button onClick={() => dispatch(increment())}>+</button>
      <button onClick={() => dispatch(decrement())}>-</button>
    </div>
  );
}

服务端状态管理:TanStack Query

import { QueryClient, QueryClientProvider, useQuery, useMutation } from '@tanstack/react-query';

const queryClient = new QueryClient();

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <UserProfile />
    </QueryClientProvider>
  );
}

function UserProfile() {
  // 自动处理 loading, error, caching, refetching
  const { data: user, isLoading, error } = useQuery({
    queryKey: ['user', 1], // 查询键
    queryFn: () => fetch('/api/user/1').then(res => res.json()),
    staleTime: 5 * 60 * 1000, // 5分钟内数据不过期
  });
  
  // 修改数据
  const updateUser = useMutation({
    mutationFn: (newUser) => 
      fetch('/api/user/1', {
        method: 'PUT',
        body: JSON.stringify(newUser),
      }).then(res => res.json()),
    onSuccess: () => {
      // 使相关查询失效,触发重新获取
      queryClient.invalidateQueries({ queryKey: ['user', 1] });
    },
  });
  
  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;
  
  return (
    <div>
      <h1>{user.name}</h1>
      <button 
        onClick={() => updateUser.mutate({ name: 'New Name' })}
      >
        Update Name
      </button>
    </div>
  );
}

4. 性能优化策略

React 渲染机制

虚拟 DOM

内存中的 DOM 表示,比对变化

协调算法

Diffing 算法,最小化 DOM 操作

并发特性

React 18+,可中断渲染

关键理解: React 的重新渲染是由状态变化触发的。当组件的 props 或 state 变化时,组件及其所有子组件都会重新渲染(除非被优化)。

避免不必要的渲染

React.memo

记忆组件,避免 props 未变时的重渲染

const ExpensiveComponent = React.memo(function ExpensiveComponent({ data }) {
  // 只在 props 变化时重新渲染
  console.log('ExpensiveComponent rendered');
  return <div>{data}</div>;
});

// 自定义比较函数
const User = React.memo(
  ({ user }) => {
    return <div>{user.name}</div>;
  },
  (prevProps, nextProps) => {
    // 只有 user.id 变化时才重新渲染
    return prevProps.user.id === nextProps.user.id;
  }
);
useMemo

记忆计算结果,避免重复计算

function ExpensiveComponent({ items, filter }) {
  const filteredItems = useMemo(() => {
    console.log('Filtering items...');
    return items.filter(item => item.includes(filter));
  }, [items, filter]); // 依赖变化时才重新计算
  
  return (
    <ul>
      {filteredItems.map(item => (
        <li key={item}>{item}</li>
      ))}
    </ul>
  );
}

更多优化技巧

useCallback

记忆回调函数,避免子组件不必要渲染

function Parent() {
  const [count, setCount] = useState(0);
  
  // ❌ 每次渲染都创建新函数
  // const handleClick = () => console.log('clicked');
  
  // ✅ 使用 useCallback
  const handleClick = useCallback(() => {
    console.log('clicked', count);
  }, [count]); // count 变化时才重新创建
  
  return <Child onClick={handleClick} />;
}

const Child = React.memo(({ onClick }) => {
  console.log('Child rendered');
  return <button onClick={onClick}>Click</button>;
});
代码分割与懒加载
// 1. React.lazy
const HeavyComponent = React.lazy(() => import('./HeavyComponent'));

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

// 2. 路由懒加载
import { lazy, Suspense } from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';

const Home = lazy(() => import('./pages/Home'));
const About = lazy(() => import('./pages/About'));

function App() {
  return (
    <Router>
      <Suspense fallback={<div>Loading...</div>}>
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/about" element={<About />} />
        </Routes>
      </Suspense>
    </Router>
  );
}

React 18 并发特性

useTransition

function App() {
  const [isPending, startTransition] = useTransition();
  const [filter, setFilter] = useState('');
  const [deferredFilter, setDeferredFilter] = useState('');
  
  const handleChange = (e) => {
    const value = e.target.value;
    setFilter(value); // 立即更新
    startTransition(() => {
      setDeferredFilter(value); // 非紧急更新
    });
  };
  
  return (
    <div>
      <input value={filter} onChange={handleChange} />
      {isPending && <div>Loading...</div>}
      <ExpensiveList filter={deferredFilter} />
    </div>
  );
}

useDeferredValue

function SearchResults({ query }) {
  const deferredQuery = useDeferredValue(query);
  
  return (
    <>
      <div>Searching for: {query}</div>
      <ExpensiveSearchResults query={deferredQuery} />
    </>
  );
}

function ExpensiveSearchResults({ query }) {
  const [results, setResults] = useState([]);
  
  useEffect(() => {
    // 耗时的搜索
    search(query).then(setResults);
  }, [query]);
  
  return (
    <ul>
      {results.map(result => (
        <li key={result.id}>{result.name}</li>
      ))}
    </ul>
  );
}

5. 路由与导航(React Router v6)

基础路由配置

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

function App() {
  return (
    <BrowserRouter>
      <nav>
        <Link to="/">Home</Link>
        <Link to="/about">About</Link>
        <Link to="/users">Users</Link>
      </nav>
      
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
        <Route path="/users" element={<Users />} />
        <Route path="/users/:id" element={<UserDetail />} />
        <Route path="*" element={<NotFound />} />
      </Routes>
    </BrowserRouter>
  );
}

嵌套路由与布局

function App() {
  return (
    <Routes>
      <Route path="/" element={<Layout />}>
        <Route index element={<Home />} />
        <Route path="dashboard" element={<Dashboard />} />
        <Route path="users" element={<Users />}>
          <Route index element={<UserList />} />
          <Route path=":id" element={<UserDetail />} />
          <Route path="new" element={<NewUser />} />
        </Route>
      </Route>
    </Routes>
  );
}

function Layout() {
  return (
    <div>
      <nav>Navigation</nav>
      <main>
        {/* Outlet 是子路由的插槽 */}
        <Outlet />
      </main>
    </div>
  );
}

路由 Hooks 与编程导航

import { 
  useParams, useNavigate, useLocation, 
  useSearchParams, useMatch 
} from 'react-router-dom';

function UserDetail() {
  // 获取路由参数
  const { id } = useParams();
  
  // 编程式导航
  const navigate = useNavigate();
  
  // 获取查询参数
  const [searchParams, setSearchParams] = useSearchParams();
  const filter = searchParams.get('filter');
  
  // 获取当前路径
  const location = useLocation();
  console.log(location.pathname);
  
  const handleEdit = () => {
    // 导航到编辑页面
    navigate(`/users/${id}/edit`);
  };
  
  const handleFilter = (newFilter) => {
    setSearchParams({ filter: newFilter });
  };
  
  return (
    <div>
      <h1>User {id}</h1>
      <button onClick={handleEdit}>Edit</button>
    </div>
  );
}

路由保护与权限控制

// components/ProtectedRoute.jsx
import { Navigate, useLocation } from 'react-router-dom';
import { useAuth } from '../hooks/useAuth';

function ProtectedRoute({ children, roles = [] }) {
  const { user, loading } = useAuth();
  const location = useLocation();
  
  if (loading) {
    return <div>Loading...</div>;
  }
  
  if (!user) {
    // 未登录,重定向到登录页
    return <Navigate to="/login" state={{ from: location }} replace />;
  }
  
  if (roles.length > 0 && !roles.includes(user.role)) {
    // 角色不符合,重定向到无权限页
    return <Navigate to="/unauthorized" replace />;
  }
  
  return children;
}

// 使用
function App() {
  return (
    <Routes>
      <Route path="/" element={<PublicLayout />}>
        <Route index element={<Home />} />
        <Route path="login" element={<Login />} />
      </Route>
      
      <Route path="/admin" element={<ProtectedRoute roles={['admin']}>
        <AdminLayout />
      </ProtectedRoute>}>
        <Route index element={<Dashboard />} />
        <Route path="users" element={<UserManagement />} />
      </Route>
    </Routes>
  );
}

6. 高级模式与最佳实践

设计模式

组件组合模式

// 1. Children 模式
function Card({ children }) {
  return <div className="card">{children}</div>;
}

function App() {
  return (
    <Card>
      <h1>Title</h1>
      <p>Content</p>
    </Card>
  );
}

// 2. Render Props
function MouseTracker({ render }) {
  const [position, setPosition] = useState({ x: 0, y: 0 });
  
  useEffect(() => {
    const handleMove = (e) => setPosition({ x: e.clientX, y: e.clientY });
    window.addEventListener('mousemove', handleMove);
    return () => window.removeEventListener('mousemove', handleMove);
  }, []);
  
  return render(position);
}

function App() {
  return (
    <MouseTracker
      render={({ x, y }) => (
        <div>
          Mouse position: {x}, {y}
        </div>
      )}
    />
  );
}

高阶组件(HOC)

// withAuth HOC
function withAuth(Component) {
  return function AuthenticatedComponent(props) {
    const { user, loading } = useAuth();
    
    if (loading) return <div>Loading...</div>;
    if (!user) return <Navigate to="/login" />;
    
    return <Component {...props} user={user} />;
  };
}

// 使用
const UserProfile = withAuth(function UserProfile({ user }) {
  return <div>Welcome, {user.name}</div>;
});

// 多个 HOC 组合
const EnhancedComponent = withRouter(
  withAuth(
    withStyles(UserProfile)
  )
);

错误边界

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false, error: null };
  }
  
  static getDerivedStateFromError(error) {
    return { hasError: true, error };
  }
  
  componentDidCatch(error, errorInfo) {
    // 上报错误到监控系统
    console.error('Error caught by boundary:', error, errorInfo);
  }
  
  render() {
    if (this.state.hasError) {
      return this.props.fallback || (
        <div>
          <h2>Something went wrong.</h2>
          <details>
            {this.state.error && this.state.error.toString()}
          </details>
        </div>
      );
    }
    
    return this.props.children;
  }
}

// 使用
function App() {
  return (
    <ErrorBoundary fallback={<div>App crashed!</div>}>
      <UnstableComponent />
    </ErrorBoundary>
  );
}

Portal

function Modal({ children, onClose }) {
  return ReactDOM.createPortal(
    <div className="modal-overlay" onClick={onClose}>
      <div className="modal-content" onClick={e => e.stopPropagation()}>
        {children}
        <button onClick={onClose}>Close</button>
      </div>
    </div>,
    document.getElementById('modal-root')
  );
}

function App() {
  const [showModal, setShowModal] = useState(false);
  
  return (
    <div>
      <button onClick={() => setShowModal(true)}>Open Modal</button>
      {showModal && (
        <Modal onClose={() => setShowModal(false)}>
          <h1>Modal Title</h1>
          <p>Modal content goes here</p>
        </Modal>
      )}
    </div>
  );
}

TypeScript 与 React

// 组件 Props 类型
interface UserCardProps {
  user: {
    id: number;
    name: string;
    email: string;
  };
  onEdit?: (id: number) => void;
  isActive?: boolean;
  tags?: string[];
}

// 函数组件
const UserCard: React.FC<UserCardProps> = ({ 
  user, 
  onEdit, 
  isActive = false,
  tags = []
}) => {
  return (
    <div className={isActive ? 'active' : ''}>
      <h2>{user.name}</h2>
      <p>{user.email}</p>
      {onEdit && (
        <button onClick={() => onEdit(user.id)}>
          Edit
        </button>
      )}
    </div>
  );
};

// 事件处理类型
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
  console.log(e.target.value);
};

const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
  e.preventDefault();
};

// 使用泛型组件
interface ListProps<T> {
  items: T[];
  renderItem: (item: T) => React.ReactNode;
}

function List<T>({ items, renderItem }: ListProps<T>) {
  return (
    <ul>
      {items.map((item, index) => (
        <li key={index}>{renderItem(item)}</li>
      ))}
    </ul>
  );
}

7. React 生态系统

现代 React 框架

N

Next.js

Full-stack 框架
  • • 服务端渲染 (SSR)
  • • 静态站点生成 (SSG)
  • • 文件系统路由
  • • API Routes
  • • 内置优化 (图片、字体)
R

Remix

全栈框架
  • • 嵌套路由
  • • 服务端状态管理
  • • 渐进式增强
  • • 数据加载优化
  • • Web 标准优先

UI 组件库

Material-UI

基于 Material Design

Ant Design

企业级 UI 设计

Chakra UI

可访问性优先

工具链与测试

Vite

下一代构建工具

Testing

Jest + React Testing Library

Storybook

组件驱动开发

8. 常见问题与最佳实践

常见问题解答

1. 如何在 useEffect 中正确处理依赖?

// ❌ 缺少依赖
useEffect(() => {
  console.log(props.userId);
}, []); // 缺少 props.userId 依赖

// ✅ 正确添加依赖
useEffect(() => {
  console.log(props.userId);
}, [props.userId]);

// ✅ 使用函数式更新避免依赖
useEffect(() => {
  const timer = setInterval(() => {
    setCount(prev => prev + 1); // 不需要 count 依赖
  }, 1000);
  return () => clearInterval(timer);
}, []);

// ✅ 将函数移到 useEffect 内部
useEffect(() => {
  const fetchData = async () => {
    const data = await fetch('/api/data');
    setData(data);
  };
  fetchData();
}, []); // 不需要 fetchData 依赖

2. 如何处理列表的 key?

// ❌ 使用索引作为 key(在列表会重排序时有问题)
{items.map((item, index) => (
  <Item key={index} item={item} />
))}

// ❌ 使用随机数(每次渲染都不同)
{items.map(item => (
  <Item key={Math.random()} item={item} />
))}

// ✅ 使用唯一且稳定的 id
{items.map(item => (
  <Item key={item.id} item={item} />
))}

// ✅ 没有 id 时生成稳定 key
{items.map(item => (
  <Item key={`${item.type}-${item.timestamp}`} item={item} />
))}

3. 如何避免状态更新时的竞态条件?

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);
  
  useEffect(() => {
    let isMounted = true; // 清理标志
    
    const fetchUser = async () => {
      const data = await fetchUser(userId);
      if (isMounted) {
        setUser(data); // 确保组件未卸载
      }
    };
    
    fetchUser();
    
    return () => {
      isMounted = false; // 清理
    };
  }, [userId]);
  
  // 或使用 AbortController
  useEffect(() => {
    const controller = new AbortController();
    
    const fetchUser = async () => {
      try {
        const data = await fetch(`/api/users/${userId}`, {
          signal: controller.signal
        });
        setUser(data);
      } catch (error) {
        if (error.name !== 'AbortError') {
          console.error('Failed to fetch user:', error);
        }
      }
    };
    
    fetchUser();
    
    return () => controller.abort();
  }, [userId]);
}

React 最佳实践

✅ 应该做

  • 小规模、单一职责组件

    每个组件只做一件事

  • 使用 TypeScript

    提高代码质量和开发体验

  • 提取自定义 Hooks

    复用逻辑,保持组件简洁

  • 错误边界处理

    优雅处理组件崩溃

❌ 应避免

  • 过度优化

    过早优化是万恶之源

  • 在 useEffect 中做太多事

    拆分副作用,保持专注

  • 直接修改 state

    总是返回新状态对象

  • 忽略 key 警告

    正确设置 key 提高性能

学习 React 的四个阶段

1

理解基础

组件、Props、State、JSX

2

掌握 Hooks

useState、useEffect、自定义 Hook

3

状态管理

Context、Zustand、Redux

4

性能优化

memo、useMemo、代码分割

最重要的建议

不要试图一次性掌握所有内容。从构建简单应用开始,遇到问题时查阅文档。React 的最佳学习方式是动手实践

互动区域

登录后可以点赞此内容

参与互动

登录后可以点赞和评论此内容,与作者互动交流