React 速查表

通过实践实验室学习 React

通过实践实验室和真实场景学习 React 前端开发。LabEx 提供全面的 React 课程,涵盖基本的组件创建、状态管理、Hooks、事件处理和性能优化。掌握为现代 Web 应用程序构建高效且可维护的用户界面。

组件创建和 JSX

函数式组件:function / =>

使用函数语法创建组件。

import React from 'react'

// 函数声明
function Welcome(props) {
  return <h1>Hello, {props.name}!</h1>
}

// 箭头函数
const Welcome = (props) => {
  return <h1>Hello, {props.name}!</h1>
}

// 简单组件的隐式返回
const Greeting = ({ name }) => <h1>Hello, {name}!</h1>

类组件:class extends React.Component

使用 ES6 类语法创建组件。

import React, { Component } from 'react'

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

// 带有构造函数的类组件
class Counter extends Component {
  constructor(props) {
    super(props)
    this.state = { count: 0 }
  }
  render() {
    return <div>Count: {this.state.count}</div>
  }
}

JSX 元素:<element>

在 JavaScript 中编写类似 HTML 的语法。

// JSX 元素
const element = <h1>Hello, world!</h1>

// 带有表达式的 JSX
const name = 'John'
const greeting = <h1>Hello, {name}!</h1>

// 多行 JSX
const element = (
  <div>
    <h1>Welcome!</h1>
    <p>Good to see you here.</p>
  </div>
)

组件导出:export default / export

导出组件以便在其他文件中使用。

// 默认导出
export default function App() {
  return <div>My App</div>
}

// 命名导出
export const Button = () => <button>Click me</button>

组件导入:import

从其他文件中导入组件。

// 导入默认组件
import App from './App'

// 导入命名组件
import { Button } from './Button'

// 导入多个组件
import React, { useState, useEffect } from 'react'

// 使用别名导入
import { Button as MyButton } from './Button'

片段 (Fragment): <React.Fragment> / <>

在不添加额外 DOM 节点的情况下对元素进行分组。

// 使用 React.Fragment
return (
  <React.Fragment>
    <h1>Title</h1>
    <p>Description</p>
  </React.Fragment>
)

// 使用简写语法
return (
  <>
    <h1>Title</h1>
    <p>Description</p>
  </>
)

Props 和组件结构

Props: props.name

将数据从父组件传递到子组件。

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

// 解构 props
function Welcome({ name, age }) {
  return (
    <h1>
      Hello, {name}! You are {age} years old.
    </h1>
  )
}

// 默认 props
function Welcome({ name = 'Guest' }) {
  return <h1>Hello, {name}!</h1>
}
测验

登录后即可答题并追踪学习进度

如何在 React 中将数据从父组件传递到子组件?
使用 state 变量
使用 props
使用 refs
使用 context API

PropTypes: Component.propTypes

验证传递给组件的 props 类型(需要 prop-types 包)。

import PropTypes from 'prop-types'

function Welcome({ name, age }) {
  return (
    <h1>
      Hello, {name}! Age: {age}
    </h1>
  )
}

Welcome.propTypes = {
  name: PropTypes.string.isRequired,
  age: PropTypes.number,
}

Welcome.defaultProps = {
  age: 18,
}

Children: props.children

访问组件开始和结束标签之间传递的内容。

// 使用 children 的组件
function Card({ children }) {
  return <div className="card">{children}</div>
}

// 用法
;<Card>
  <h2>Title</h2>
  <p>Content here</p>
</Card>

状态管理和 Hooks

useState Hook: useState()

向函数式组件添加状态。

import React, { useState } from 'react'

function Counter() {
  const [count, setCount] = useState(0)
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  )
}

// 多个状态变量
function Form() {
  const [name, setName] = useState('')
  const [email, setEmail] = useState('')
}
测验

登录后即可答题并追踪学习进度

useState(0) 返回什么?
一个包含状态值和更新函数的数组
仅状态值
一个更新状态的函数
什么都不返回,它只设置状态

useEffect Hook: useEffect()

在函数式组件中执行副作用操作。

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

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

  // 效果在每次渲染后运行
  useEffect(() => {
    document.title = `Count: ${count}`
  })

  // 带有清理函数的副作用
  useEffect(() => {
    const timer = setInterval(() => setCount((c) => c + 1), 1000)
    return () => clearInterval(timer)
  }, [])
}
测验

登录后即可答题并追踪学习进度

useEffect(() => {...}, []) 中的空依赖数组 [] 是什么意思?
效果在每次渲染时运行
效果从不运行
效果运行两次
效果仅在初始渲染后运行一次

类组件状态:this.state / setState()

在类组件中管理状态。

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>
    )
  }
}

自定义 Hooks: use...

创建可重用的有状态逻辑。

// 自定义 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 }
}

// 用法
function Counter() {
  const { count, increment, decrement, reset } = useCounter(0)
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>+</button>
      <button onClick={decrement}>-</button>
      <button onClick={reset}>Reset</button>
    </div>
  )
}

事件处理

测验

登录后即可答题并追踪学习进度

PropTypes 在 React 中的目的是什么?
验证传递给组件的 props 的类型
提高组件性能
自动样式化组件
使组件运行更快

点击事件:onClick

处理按钮点击和元素交互。

function Button() {
  const handleClick = () => {
    alert('Button clicked!')
  }
  return <button onClick={handleClick}>Click me</button>
}

// 内联事件处理程序
function Button() {
  return <button onClick={() => alert('Clicked!')}>Click me</button>
}

// 传递参数
function Button() {
  const handleClick = (message) => {
    alert(message)
  }
  return <button onClick={() => handleClick('Hello!')}>Click me</button>
}

表单事件:onChange / onSubmit

处理表单输入和提交。

function Form() {
  const [value, setValue] = useState('')
  const handleChange = (e) => {
    setValue(e.target.value)
  }
  const handleSubmit = (e) => {
    e.preventDefault()
    console.log('Submitted:', value)
  }
  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        value={value}
        onChange={handleChange}
        placeholder="Enter text"
      />
      <button type="submit">Submit</button>
    </form>
  )
}

事件对象:event.target / event.preventDefault()

访问事件属性并控制默认行为。

function handleInput(event) {
  console.log('Input value:', event.target.value)
  console.log('Input name:', event.target.name)
}

function handleFormSubmit(event) {
  event.preventDefault() // 阻止表单提交
  console.log('Form submitted')
}

// 事件委托
function List() {
  const handleClick = (event) => {
    if (event.target.tagName === 'BUTTON') {
      console.log('Button clicked:', event.target.textContent)
    }
  }
  return (
    <div onClick={handleClick}>
      <button>Button 1</button>
      <button>Button 2</button>
    </div>
  )
}

键盘事件:onKeyDown / onKeyUp

响应键盘交互。

function KeyboardHandler() {
  const handleKeyDown = (event) => {
    if (event.key === 'Enter') {
      console.log('Enter key pressed')
    }
    if (event.ctrlKey && event.key === 's') {
      event.preventDefault()
      console.log('Ctrl+S pressed')
    }
  }
  return <input onKeyDown={handleKeyDown} placeholder="Type here..." />
}

条件渲染

条件运算符:&& / ?:

根据条件显示/隐藏元素。

function Greeting({ user }) {
  return (
    <div>
      {user && <h1>Welcome, {user.name}!</h1>}
      {!user && <h1>Please log in</h1>}
    </div>
  )
}

// 三元运算符
function Status({ isOnline }) {
  return <div>User is {isOnline ? 'online' : 'offline'}</div>
}

If/Else 逻辑:if 语句

使用传统的 JavaScript 逻辑处理复杂条件。

function UserProfile({ user, isAdmin }) {
  if (!user) {
    return <div>Loading...</div>
  }
  if (isAdmin) {
    return <AdminPanel user={user} />
  }
  return <UserPanel user={user} />
}

// 提前返回模式
function Component({ data }) {
  if (!data) return null
  if (data.error) return <ErrorMessage />
  return <DataDisplay data={data} />
}

Switch 语句:switch

高效处理多个条件。

function StatusIcon({ status }) {
  switch (status) {
    case 'loading':
      return <Spinner />
    case 'success':
      return <CheckIcon />
    case 'error':
      return <ErrorIcon />
    default:
      return null
  }
}

动态样式:条件 CSS

根据组件状态或 props 应用样式。

function Button({ variant, disabled }) {
  const className = `btn ${variant} ${disabled ? 'disabled' : ''}`
  return (
    <button
      className={className}
      style={{
        backgroundColor: variant === 'primary' ? 'blue' : 'gray',
        opacity: disabled ? 0.5 : 1,
      }}
      disabled={disabled}
    >
      Click me
    </button>
  )
}

列表渲染和 Key

Map 函数:array.map()

根据数组数据渲染组件列表。

function TodoList({ todos }) {
  return (
    <ul>
      {todos.map((todo) => (
        <li key={todo.id}>{todo.text}</li>
      ))}
    </ul>
  )
}

// 使用索引(应尽量避免)
function ItemList({ items }) {
  return (
    <ul>
      {items.map((item, index) => (
        <li key={index}>{item}</li>
      ))}
    </ul>
  )
}

Key: key 属性

为列表项提供唯一的标识符以优化渲染。

// 好:使用唯一 ID
function UserList({ users }) {
  return (
    <ul>
      {users.map((user) => (
        <li key={user.id}>
          <UserCard user={user} />
        </li>
      ))}
    </ul>
  )
}

// 创建复合 key
function CommentList({ comments }) {
  return (
    <div>
      {comments.map((comment) => (
        <Comment key={`${comment.postId}-${comment.id}`} comment={comment} />
      ))}
    </div>
  )
}

Filter 和 Map: 数组方法

在渲染之前处理数组。

function TaskList({ tasks, showCompleted }) {
  const filteredTasks = showCompleted
    ? tasks
    : tasks.filter((task) => !task.completed)
  return (
    <ul>
      {filteredTasks.map((task) => (
        <li key={task.id} className={task.completed ? 'completed' : ''}>
          {task.title}
        </li>
      ))}
    </ul>
  )
}

空状态:处理空数组

在列表为空时显示适当的内容。

function ProductList({ products }) {
  if (products.length === 0) {
    return <div>No products found.</div>
  }
  return (
    <div>
      {products.map((product) => (
        <ProductCard key={product.id} product={product} />
      ))}
    </div>
  )
}

性能优化

React.memo: React.memo()

防止函数式组件不必要的重新渲染。

const ExpensiveComponent = React.memo(function ExpensiveComponent({ data }) {
  return <div>{/* Complex rendering logic */}</div>
})

// 使用自定义比较函数
const MyComponent = React.memo(
  function MyComponent({ user }) {
    return <div>{user.name}</div>
  },
  (prevProps, nextProps) => {
    return prevProps.user.id === nextProps.user.id
  },
)

useMemo Hook: useMemo()

记忆化昂贵的计算。

function ExpensiveList({ items, searchTerm }) {
  const filteredItems = useMemo(() => {
    return items.filter((item) =>
      item.name.toLowerCase().includes(searchTerm.toLowerCase()),
    )
  }, [items, searchTerm])
  return (
    <ul>
      {filteredItems.map((item) => (
        <li key={item.id}>{item.name}</li>
      ))}
    </ul>
  )
}

useCallback Hook: useCallback()

记忆化函数引用以防止不必要的重新渲染。

function Parent({ items }) {
  const [count, setCount] = useState(0)
  const handleItemClick = useCallback((itemId) => {
    console.log('Item clicked:', itemId)
  }, []) // 空依赖数组
  return (
    <div>
      <button onClick={() => setCount(count + 1)}>Count: {count}</button>
      <ItemList items={items} onItemClick={handleItemClick} />
    </div>
  )
}

懒加载:React.lazy() / Suspense

仅在需要时加载组件以减小包大小。

const LazyComponent = React.lazy(() => import('./LazyComponent'))

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

组件通信

Props 向下:父到子

将数据从父组件传递到子组件。

function Parent() {
  const [user, setUser] = useState({ name: 'John', age: 30 })
  return (
    <div>
      <ChildComponent user={user} />
      <AnotherChild userName={user.name} />
    </div>
  )
}

function ChildComponent({ user }) {
  return <div>Hello, {user.name}!</div>
}

回调向上:子到父

将数据从子组件发送回父组件。

function Parent() {
  const [message, setMessage] = useState('')
  const handleChildMessage = (msg) => {
    setMessage(msg)
  }
  return (
    <div>
      <p>Message: {message}</p>
      <Child onMessage={handleChildMessage} />
    </div>
  )
}

function Child({ onMessage }) {
  return (
    <button onClick={() => onMessage('Hello from child!')}>Send Message</button>
  )
}

Context API: createContext / useContext

在不进行 prop 逐层传递的情况下共享多个组件的状态。

const UserContext = React.createContext()

function App() {
  const [user, setUser] = useState({ name: 'John' })
  return (
    <UserContext.Provider value={{ user, setUser }}>
      <Header />
      <Main />
    </UserContext.Provider>
  )
}

function Header() {
  const { user } = useContext(UserContext)
  return <h1>Welcome, {user.name}!</h1>
}

Refs: useRef / forwardRef

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

function TextInput() {
  const inputRef = useRef(null)
  const focusInput = () => {
    inputRef.current.focus()
  }
  return (
    <div>
      <input ref={inputRef} type="text" />
      <button onClick={focusInput}>Focus Input</button>
    </div>
  )
}

// 转发 refs
const FancyInput = forwardRef((props, ref) => (
  <input className="fancy" ref={ref} {...props} />
))

开发工具和调试

React DevTools: 浏览器扩展

调试 React 组件并检查组件树。

// 安装 React DevTools 浏览器扩展
// Components 选项卡:检查组件层次结构
// Profiler 选项卡:测量性能

// 控制台调试
function MyComponent(props) {
  console.log('MyComponent props:', props)
  console.log('MyComponent rendered')
  return <div>{props.children}</div>
}

错误边界 (Error Boundaries): componentDidCatch

捕获组件树中的 JavaScript 错误并显示备用 UI。

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props)
    this.state = { hasError: false }
  }
  static getDerivedStateFromError(error) {
    return { hasError: true }
  }
  componentDidCatch(error, errorInfo) {
    console.log('Error caught:', error, errorInfo)
  }
  render() {
    if (this.state.hasError) {
      return <h1>Something went wrong.</h1>
    }
    return this.props.children
  }
}

严格模式 (Strict Mode): React.StrictMode

为开发启用额外的检查和警告。

import React from 'react'
import ReactDOM from 'react-dom'

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

分析 (Profiling): 性能测量

测量组件性能并识别瓶颈。

// 使用 React DevTools Profiler
// 包裹组件以进行分析
import { Profiler } from 'react'

function onRenderCallback(id, phase, actualDuration) {
  console.log('Component', id, 'took', actualDuration, 'ms')
}

;<Profiler id="App" onRender={onRenderCallback}>
  <App />
</Profiler>

React 安装和设置

Create React App: npx create-react-app

快速启动新的 React 项目。

# 创建新的 React 应用
npx create-react-app my-app
cd my-app

# 启动开发服务器
npm start

# 构建生产版本
npm run build

# 运行测试
npm test

Vite: npm create vite@latest

用于 React 项目的快速构建工具和开发服务器。

# 创建新的 Vite React 应用
npm create vite@latest my-react-app -- --template react
cd my-react-app
npm install

# 启动开发服务器
npm run dev

# 构建生产版本
npm run build

手动设置/导入

将 React 添加到现有项目或使用 CDN。

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

# 用于开发
npm install --save-dev @vitejs/plugin-react
// 基本 React 导入
import React from 'react'
import ReactDOM from 'react-dom'

// 渲染到 DOM
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(<App />)

高级模式和特性

高阶组件 (HOC)

通过包装组件来重用组件逻辑。

function withLoading(WrappedComponent) {
  return function WithLoadingComponent(props) {
    if (props.isLoading) {
      return <div>Loading...</div>
    }
    return <WrappedComponent {...props} />
  }
}

// 用法
const UserListWithLoading = withLoading(UserList)
;<UserListWithLoading users={users} isLoading={loading} />

Render Props 模式

通过将 prop 的值设置为函数来在组件之间共享代码。

function DataFetcher({ render, url }) {
  const [data, setData] = useState(null)
  const [loading, setLoading] = useState(true)
  useEffect(() => {
    fetch(url)
      .then((res) => res.json())
      .then((data) => {
        setData(data)
        setLoading(false)
      })
  }, [url])
  return render({ data, loading })
}

// 用法
;<DataFetcher
  url="/api/users"
  render={({ data, loading }) =>
    loading ? <Spinner /> : <UserList users={data} />
  }
/>

复合组件 (Compound Components)

创建协同工作的组件单元。

function Tabs({ children, activeTab }) {
  return (
    <div className="tabs">
      {React.Children.map(children, (child, index) =>
        React.cloneElement(child, { isActive: index === activeTab }),
      )}
    </div>
  )
}

function Tab({ children, isActive }) {
  return <div className={`tab ${isActive ? 'active' : ''}`}>{children}</div>
}

// 用法
;<Tabs activeTab={0}>
  <Tab>Tab 1 Content</Tab>
  <Tab>Tab 2 Content</Tab>
</Tabs>

Portal: ReactDOM.createPortal()

将子组件渲染到父组件层次结构之外的 DOM 节点中。

import ReactDOM from 'react-dom'

function Modal({ children, isOpen }) {
  if (!isOpen) return null
  return ReactDOM.createPortal(
    <div className="modal-overlay">
      <div className="modal">{children}</div>
    </div>,
    document.getElementById('modal-root'),
  )
}

组合优于继承

使用组合模式而不是扩展类。

// 好:组合
function Button({ variant, children, ...props }) {
  return (
    <button className={`btn btn-${variant}`} {...props}>
      {children}
    </button>
  )
}

function IconButton({ icon, children, ...props }) {
  return (
    <Button {...props}>
      <Icon name={icon} />
      {children}
    </Button>
  )
}

组件模式:灵活的 API

设计易于使用的灵活组件 API。

// 灵活的 Card 组件
function Card({ header, children, footer, variant = 'default' }) {
  return (
    <div className={`card card-${variant}`}>
      {header && <div className="card-header">{header}</div>}
      <div className="card-body">{children}</div>
      {footer && <div className="card-footer">{footer}</div>}
    </div>
  )
}

// 用法
;<Card header={<h3>Title</h3>} footer={<Button>Action</Button>}>
  Card content here
</Card>

相关链接