前言
React 的“常用语法”本质上就是一组稳定的写法:用 JSX 描述 UI,用组件拆分页面,用 props/state 驱动渲染,用 Hook 管理状态与副作用。
下面用一份“速查 + 最小示例”的方式,把日常开发里最常见的写法汇总起来。
JSX 要点
- 表达式嵌入:用
{} 包住变量或表达式
1 2 3 4
| const name = "Alice"; export default function Demo() { return <div>你好,{name}</div>; }
|
- 属性命名:HTML 里的
class 在 JSX 中写成 className
1 2 3
| export default function Demo() { return <div className="card">内容</div>; }
|
- 条件/循环通常不写在 JSX 内部“复杂逻辑”,尽量提前算好或用表达式包裹
样式绑定
React 里最常见的两种样式绑定是:style(内联)和 className(类名)。
内联 style
style 接收一个对象,字段名用驼峰命名(例如 fontSize):
1 2 3 4 5 6 7 8 9
| export default function InlineStyleDemo({ color }) { const size = 16;
return ( <p style={{ color, fontSize: size, margin: 0 }}> 这是一段内联样式 </p> ); }
|
要点:
style 对象可以是动态的(依赖 props/state)
- 数值通常是像素值(例如
fontSize: 16)
className 条件
当样式需要根据状态切换时,常用模式是“条件表达式拼接类名”:
1 2 3 4 5
| export default function ClassNameDemo({ ok }) { const cls = ok ? "btn btn-ok" : "btn btn-bad";
return <button className={cls}>{ok ? "通过" : "失败"}</button>; }
|
也可以用模板字符串:
1 2 3 4 5 6 7
| export default function ClassNameDemo({ active }) { return ( <div className={`card ${active ? "card--active" : ""}`}> 状态样式 </div> ); }
|
组件写法
最常见的是函数组件(Function Component):
1 2 3
| export default function Button({ text, onClick }) { return <button onClick={onClick}>{text}</button>; }
|
组件可以复用,也可以组合多个子组件形成页面结构。
Props 使用
props 是“父组件传给子组件的数据 + 回调”。常见写法:
- 解构 props 参数
1 2 3 4 5 6 7 8
| function Card({ title, children }) { return ( <section> <h3>{title}</h3> <div>{children}</div> </section> ); }
|
- 传回调:让子组件“通知”父组件发生了什么
1 2 3 4 5 6 7
| function App() { function handleSave() { console.log("保存"); }
return <button onClick={handleSave}>保存</button>; }
|
State(useState)
用 useState 声明状态,并用更新函数修改状态:
1 2 3 4 5 6 7 8 9 10 11 12
| import { useState } from "react";
export default function Counter() { const [count, setCount] = useState(0);
return ( <div> <p>当前:{count}</p> <button onClick={() => setCount((c) => c + 1)}>+1</button> </div> ); }
|
要点:
- 直接修改状态值(如
count++)是错误的
- 若更新依赖旧值,建议用函数式更新:
setX((prev) => ...)
多状态
最常见的做法是:在同一个组件里调用多个 useState,分别管理互不影响的状态。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| import { useState } from "react";
export default function MultiStateDemo() { const [count, setCount] = useState(0); const [text, setText] = useState(""); const [loading, setLoading] = useState(false);
async function handleSend() { setLoading(true); try { await new Promise((r) => setTimeout(r, 500)); console.log("发送:", text); setCount((c) => c + 1); setText(""); } finally { setLoading(false); } }
return ( <div style={{ padding: 12 }}> <p>count:{count}</p>
<input value={text} onChange={(e) => setText(e.target.value)} placeholder="输入内容" style={{ marginRight: 8 }} />
<button onClick={handleSend} disabled={loading}> {loading ? "发送中..." : "发送"} </button> </div> ); }
|
对象 state(可选)
如果多个状态属于同一个“表单/数据块”,也可以把它们放到一个对象里管理(更新时用展开运算符合并)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| import { useState } from "react";
export default function FormObjectDemo() { const [form, setForm] = useState({ name: "", age: 0 });
return ( <div> <input value={form.name} onChange={(e) => setForm({ ...form, name: e.target.value })} placeholder="姓名" /> <input type="number" value={form.age} onChange={(e) => setForm({ ...form, age: Number(e.target.value) })} placeholder="年龄" /> <p> {form.name}({form.age}) </p> </div> ); }
|
事件处理
在 JSX 中监听事件:onClick、onChange 等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import { useState } from "react";
export default function FormDemo() { const [text, setText] = useState("");
return ( <div> <input value={text} onChange={(e) => setText(e.target.value)} placeholder="输入点内容" /> <p>你输入:{text}</p> </div> ); }
|
条件渲染
常见三种写法:
if 提前返回
1 2 3 4
| export default function Status({ ok }) { if (!ok) return <p>失败</p>; return <p>成功</p>; }
|
- 三元运算符
1 2 3
| export default function Status({ ok }) { return <p>{ok ? "成功" : "失败"}</p>; }
|
&&(适合短内容)
1 2 3
| export default function Tips({ show }) { return <div>{show && <p>提示:这是一个小弹窗</p>}</div>; }
|
列表渲染
当你把数组变成一组元素,通常用 map,并给每一项一个稳定的 key:
1 2 3 4 5 6 7 8 9
| export default function List({ items }) { return ( <ul> {items.map((item) => ( <li key={item.id}>{item.name}</li> ))} </ul> ); }
|
要点:
key 应该使用“业务稳定且唯一”的值(例如数据库 id)
- 不要用索引当 key(除非列表绝不会重排且短期场景可控)
useEffect(副作用)
副作用例子:请求接口、订阅事件、读取本地存储、设置定时器等。
- 组件首次渲染后执行一次:依赖数组
[]
1 2 3 4 5 6 7 8 9 10 11 12 13
| import { useEffect, useState } from "react";
export default function User() { const [name, setName] = useState("");
useEffect(() => { fetch("https://jsonplaceholder.typicode.com/users/1") .then((r) => r.json()) .then((data) => setName(data.name)); }, []);
return <p>用户名:{name}</p>; }
|
- 依赖变化时重新执行:依赖数组放变量
1 2 3
| useEffect(() => { console.log("id 变化:", id); }, [id]);
|
- 清理函数:返回一个函数,适合取消订阅/清理定时器
1 2 3 4
| useEffect(() => { const timer = setInterval(() => console.log("tick"), 1000); return () => clearInterval(timer); }, []);
|
Hooks
除了 useState/useEffect,日常还常用这些 Hook:
useRef
用于保存“不会触发渲染的值”或“DOM 引用”(比如直接聚焦输入框):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import { useRef } from "react";
export default function FocusInput() { const inputRef = useRef(null);
function focus() { inputRef.current?.focus(); }
return ( <div> <input ref={inputRef} placeholder="点按钮聚焦" /> <button onClick={focus}>聚焦</button> </div> ); }
|
useContext
用于在组件树中“免传多层 props”共享数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import { createContext, useContext, useState } from "react";
const ThemeContext = createContext("light");
function ThemeLabel() { const theme = useContext(ThemeContext); return <p>当前主题:{theme}</p>; }
export default function ThemeProviderDemo() { const [theme, setTheme] = useState("light");
return ( <ThemeContext.Provider value={theme}> <ThemeLabel /> <button onClick={() => setTheme("dark")}>切换到 dark</button> </ThemeContext.Provider> ); }
|
useMemo
用于缓存“计算结果”,避免每次渲染都重复计算(适合昂贵计算):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import { useMemo, useState } from "react";
export default function ExpensiveCalc() { const [n, setN] = useState(1);
const result = useMemo(() => { let sum = 0; for (let i = 0; i < 100000; i++) sum += i; return sum + n; }, [n]);
return ( <div> <p>结果:{result}</p> <button onClick={() => setN((x) => x + 1)}>n+1</button> </div> ); }
|
useCallback
用于缓存“函数引用”,常用于把回调传给子组件以减少不必要的渲染:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| import { useCallback, useState } from "react";
function Child({ onAction }) { return <button onClick={onAction}>执行</button>; }
export default function Parent() { const [count, setCount] = useState(0);
const onAction = useCallback(() => { setCount((c) => c + 1); }, []);
return ( <div> <p>count:{count}</p> <Child onAction={onAction} /> </div> ); }
|
useReducer
适合更复杂的状态逻辑:用“reducer(state, action) 更新”替代一堆 setState:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| import { useReducer } from "react";
function reducer(state, action) { switch (action.type) { case "inc": return { count: state.count + 1 }; case "reset": return { count: 0 }; default: return state; } }
export default function ReducerDemo() { const [state, dispatch] = useReducer(reducer, { count: 0 });
return ( <div> <p>count:{state.count}</p> <button onClick={() => dispatch({ type: "inc" })}>+1</button> <button onClick={() => dispatch({ type: "reset" })}>重置</button> </div> ); }
|
自定义 Hook
把重复逻辑封装成 useXxx,在内部自由使用 Hook,再把结果 return 给组件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import { useState } from "react";
function useCounter(initial = 0) { const [count, setCount] = useState(initial); const inc = () => setCount((c) => c + 1); return { count, inc }; }
export default function Demo() { const { count, inc } = useCounter(0); return ( <div> <p>count:{count}</p> <button onClick={inc}>+1</button> </div> ); }
|
规则提醒
- Hook 必须在组件或自定义 Hook 的最外层调用:不要写在条件/循环里
useEffect 的依赖数组要尽量写对,否则会导致重复执行或数据不同步
常见最佳实践
- 状态更新优先使用“不可变”思维:复制数组/对象再更新
- 尽量让组件职责单一:UI 组件只负责展示,逻辑可以拆到自定义 Hook 或上层组件
- 将“重复逻辑”抽成函数/组件,避免在多个地方复制粘贴
- 让 key 保持稳定,减少不必要的 DOM 重建
快速小抄
- JSX:
{表达式}、className
- 组件:函数组件
export default function X() {}
- props:子组件接收,父组件传入数据/回调
- state:
const [x, setX] = useState(...)
- 事件:
onClick/onChange + 事件参数 e
- 条件:
if / 三元 / &&
- 列表:
items.map(...) + 稳定 key
- 副作用:
useEffect(() => {...}, deps) + 清理 return () => ...