Skip to content

React 核心概念

一、React 是什么

React 是一个 UI 库,核心思想:UI = f(state)——页面是状态的函数。状态一变,React 重新执行组件函数,算出新页面。

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

二、JSX:在 JS 里写 HTML

JSX 是 React 的模板方案——HTML 语法直接写在 JS 里,最终被编译成 JS 函数调用。

jsx
const product = { name: '手机', price: 3999, inStock: true }

function ProductCard({ p }: { p: Product }) {
  return (
    <div className="card">                      {/* 注意:class 写 className */}
      <h3>{p.name}</h3>
      <p className="price">¥{p.price}</p>
      {p.inStock ? <button>加购</button> : <span>已售罄</span>}
    </div>
  )
}

JSX 规则速记:

  • 动态内容用 {} 包裹
  • 属性名用驼峰:classNameonClick
  • 循环用 map 生成,key 必填
  • 条件渲染用三元表达式 / &&

三、useState:组件状态

状态改变 → 组件重新渲染(这是 React 与 Vue 最大的心智差异)。

jsx
const [keyword, setKeyword] = useState('')
const [page, setPage] = useState(1)
const [products, setProducts] = useState<Product[]>([])

不可变更新

React 更新状态要"造新值",不要直接改原对象:

jsx
// ❌ 错误:直接改,React 感知不到
cartItems[0].count = 3
setCartItems(cartItems)

// ✅ 正确:生成新数组
setCartItems(cartItems.map((item) =>
  item.id === 1 ? { ...item, count: 3 } : item,
))

四、useEffect:副作用

发请求、订阅事件等"副作用"要放在 useEffect 里。它相当于 Vue 的 onMounted + watch

jsx
import { useState, useEffect } from 'react'

function ProductList() {
  const [products, setProducts] = useState<Product[]>([])

  // 依赖数组为 []:只在组件挂载后执行一次
  useEffect(() => {
    fetch('/api/product/list')
      .then((res) => res.json())
      .then((data) => setProducts(data.data.records))
  }, [])
}

依赖数组的规则(面试必问):

jsx
useEffect(() => { ... }, [])       // 挂载时执行一次
useEffect(() => { ... }, [keyword]) // keyword 变化时执行
useEffect(() => {
  return () => { /* 清理函数:相当于 Vue 的 onBeforeUnmount */ }
}, [])

五、props 与回调

React 父子通信 = props 传数据,回调函数传事件

jsx
// 子组件
function ProductCard({ p, onAdd }: { p: Product; onAdd: (id: number) => void }) {
  return <button onClick={() => onAdd(p.id)}>加购</button>
}

// 父组件
function Home() {
  const [products, setProducts] = useState<Product[]>([])
  const handleAdd = (id: number) => { /* 加购逻辑 */ }
  return (
    <div>
      {products.map((p) => <ProductCard key={p.id} p={p} onAdd={handleAdd} />)}
    </div>
  )
}

六、常用 Hooks 总览

Hook作用对应 Vue
useState声明状态ref
useEffect副作用/请求onMounted/watch
useMemo缓存计算结果computed
useCallback缓存函数computed(函数场景)
useRef保存可变值/拿 DOMref(DOM 场景)
useContext跨层传递数据provide/inject

useMemo(对应 computed,防重复计算):

jsx
const totalPrice = useMemo(
  () => cartItems.reduce((sum, i) => sum + i.price * i.count, 0),
  [cartItems],
)

七、完整小例子:商品列表页

jsx
import { useState, useEffect } from 'react'

interface Product { id: number; name: string; price: number; stock: number }

export default function Home() {
  const [products, setProducts] = useState<Product[]>([])
  const [loading, setLoading] = useState(true)

  useEffect(() => {
    setLoading(true)
    fetch('/api/product/list')
      .then((res) => res.json())
      .then((data) => setProducts(data.data.records))
      .finally(() => setLoading(false))
  }, [])

  if (loading) return <div>加载中...</div>

  return (
    <div className="grid">
      {products.map((p) => (
        <div className="card" key={p.id}>
          {p.name} ¥{p.price}
        </div>
      ))}
    </div>
  )
}

本章小结

React 三大件:useState(状态)、useEffect(请求)、map 渲染列表。加上不可变更新的习惯,就能写出商城的大部分功能。

基于 MIT 协议发布,可自由学习与修改