认识 React 的设计理念
以函数为中心,声明式 UI,组件树结构,单向数据流
与 Vue 对比:Vue 更“魔法”(响应式追踪),React 更“显式”
场景对比
依赖收集(Vue 的响应式 vs React 的 state)
vue
import { ref, reactive, computed } from 'vue'
const count = ref(0)
const state = reactive({ name: 'Alice' })
const double = computed(() => count.value * 2)
react
import { useState, useMemo } from 'react'
function Counter() {
const [count, setCount] = useState(0)
// 类似 computed
const double = useMemo(() => count * 2, [count])
return (
<div>
<p>{count}</p>
<p>{double}</p>
<button onClick={() => setCount(count + 1)}>增加</button>
</div>
)
}
父组件触发子组件
vue
<Child ref="childRef" />
<script setup>
const childRef = ref(null)
function triggerChild() {
childRef.value.sayHi()
}
</script>
react
import { forwardRef, useImperativeHandle, useRef } from 'react'
const Child = forwardRef((props, ref) => {
useImperativeHandle(ref, () => ({
sayHi: () => alert('Hi from Child!')
}))
return <div>Child Component</div>
})
function Parent() {
const childRef = useRef(null)
return (
<div>
<Child ref={childRef} />
<button onClick={() => childRef.current.sayHi()}>触发子组件</button>
</div>
)
}
子组件触发父组件事件(事件向上传递)
vue
<Child @custom-event="handleEvent" />
// Child
emit('custom-event', data)
react
function Child({ onCustomEvent }) {
return <button onClick={() => onCustomEvent('Hello')}>触发父组件</button>
}
function Parent() {
function handleEvent(data) {
alert(data)
}
return <Child onCustomEvent={handleEvent} />
}
watch(监听变化)
vue
watch(() => state.name, (newVal, oldVal) => { ... })
react
import { useEffect, useState } from 'react'
function Demo() {
const [name, setName] = useState('Alice')
useEffect(() => {
console.log('name 改变了:', name)
}, [name]) // 依赖数组决定监听谁
return <input value={name} onChange={e => setName(e.target.value)} />
}
样式定义
vue
<template>
<div :class="{ active: isActive }" :style="{ color: color }">Text</div>
</template>
<script setup>
const isActive = ref(true)
const color = ref('red')
</script>
react
function Demo() {
const [isActive, setIsActive] = useState(true)
const color = 'red'
return (
<div
className={isActive ? 'active' : ''}
style={{ color: color }}
>
Text
</div>
)
}
上下文
vue
<script setup>
import { provide, inject } from 'vue'
const theme = 'dark'
provide('theme', theme)
</script>
<!-- 子组件 -->
<script setup>
const theme = inject('theme')
console.log(theme) // 'dark'
</script>
react
- createContext
- useContext
import {createContext} from 'react';
interface ThemeContextType {
dark: boolean;
switchTheme: () => void;
}
export const AlgorithmContext = createContext<ThemeContextType>({
dark: false,
switchTheme: () => {},
});
export const RootApp = () => {
// 用 state 管理主题
const {defaultAlgorithm, darkAlgorithm} = theme;
const [algorithm, setAlgorithm] = useState(() => defaultAlgorithm);
const [dark, setDark] = useState(false)
const switchTheme = () => {
if (dark) {
setDark(false)
setAlgorithm(() => defaultAlgorithm);
} else {
setDark(true)
setAlgorithm(() => darkAlgorithm);
}
};
return (
<AlgorithmContext.Provider value={{dark, switchTheme}}>
<ConfigProvider theme={{
algorithm
}}>
<FuseChatApp/>
</ConfigProvider>
</AlgorithmContext.Provider>
)
}
export default function ChatHeader() {
const {dark, switchTheme} = useContext(AlgorithmContext);
return (
<div className="flex items-center justify-end gap-2 px-10">
<Button
shape="circle"
icon={<CheckSquareOutlined/>}
/>
<Button
shape="circle"
onClick={switchTheme}
icon={
dark ? (
<MoonOutlined/>
) : (
<SunOutlined/>
)
}
/>
<Button shape="circle"
icon={<SettingOutlined/>}
/>
</div>
);
}
📚 与 Vue 对比梳理(便于理解)
| 特性 | Vue | React |
|---|---|---|
| 模板语法 | 模板字符串 | JSX(更灵活的 JS) |
| 数据响应式 | 自动收集依赖 | 显式设置 useState、useEffect |
| 事件绑定 | @click="fn" | onClick={fn} |
| 组件通信 | props / emit | props / 回调函数 |
| 生命周期 | created, mounted 等 | useEffect |
useState
在 vue 中回自动收集依赖,但是在 react 中是没有的,要使用 useState
// 第一个参数是数据,第二个是赋值
const [count, setCount] = useState(0);
useMemo
useMemo 用来 缓存计算结果,避免不必要的重复计算。
就像 Vue 中的 computed 属性,用于缓存函数返回值。
🧩 对比:Vue computed vs React useMemo
| 特性 | Vue computed | React useMemo |
|---|---|---|
| 是否懒计算 | ✅ 是 | ✅ 是 |
| 依赖变了才更新 | ✅ | ✅ |
| 适用对象 | 模板绑定的值 | 任何计算(变量、函数) |
useEffect
🧪 一句话解释 useEffect
useEffect(fn, deps) 的意思是:当组件渲染后,执行 fn;当 deps 变化时,再次执行。
在 Vue 中你有 mounted()、watch()、beforeDestroy() 这些生命周期方法。而 React 函数组件默认没有生命周期 —— 所以就用 useEffect() 来统一处理这些副作用逻辑。
| 写法 | 含义 | 类似 Vue 生命周期 |
|---|---|---|
useEffect(() => {...}) | 每次渲染后都执行 | updated |
useEffect(() => {...}, []) | 仅首次执行一次 | mounted |
useEffect(() => {...}, [a, b]) | a 或 b 变化时执行 | watch |
return () => {...} | 组件卸载前执行,做清理操作 | beforeDestroy |
父子组件
React 中数据是“单向流动”的(单向数据流):父组件可以通过 props 把数据传给子组件,但 子组件不能直接修改父组件的数据。
但我们可以通过一种方式让子组件“修改”父组件的值:让父组件把修改函数也传下去,子组件调用这个函数来“通知”父组件修改。
function Child({ count, onChange }) {
return (
<div>
<p>子组件收到的 count:{count}</p>
<button onClick={() => onChange(count + 1)}>+1</button>
<button onClick={() => onChange(0)}>重置</button>
</div>
);
}
import { useState } from 'react';
import Child from './Child';
function Parent() {
const [count, setCount] = useState(0);
const handleChange = (newCount) => {
setCount(newCount);
};
return (
<div>
<h2>父组件 Count:{count}</h2>
<Child count={count} onChange={handleChange} />
</div>
);
}
Provider
Provider 是 React 中 Context 上下文机制 的一部分,用于让组件树中的任何子组件都能访问到某个值,不用一层层通过 props 传递。
比如:
- 全局用户信息
- 多语言(i18n)
- 主题设置(light/dark)
- 登录状态
- 全局弹窗控制
- 跨页面共享状态(不用 redux)
1️⃣ 创建上下文
import { createContext } from 'react';
export const UserContext = createContext(null);
2️⃣ 提供值(在最外层包一层 Provider)
import { useState } from 'react';
import { UserContext } from './UserContext';
import Profile from './Profile';
function App() {
const [user, setUser] = useState({ name: '小明', age: 25 });
return (
<UserContext.Provider value={user}>
<Profile />
</UserContext.Provider>
);
}
3️⃣ 在任意子组件中使用 useContext 获取值
import { useContext } from 'react';
import { UserContext } from './UserContext';
function Profile() {
const user = useContext(UserContext);
return <h2>用户名是:{user.name}</h2>;
}
对比 Vue
| 功能 | Vue 写法 | React 写法 |
|---|---|---|
| 提供全局值 | provide('xxx', 值) | <MyContext.Provider value={值}> |
| 注入全局值 | inject('xxx') | useContext(MyContext) |
| 全局状态管理推荐 | vuex / pinia | context / redux / zustand |
useTransition
useTransition 是 React 的并发特性之一,主要用于控制「非紧急更新」,让 UI 更加流畅。
import { useTransition, useState } from 'react';
function App() {
const [input, setInput] = useState('');
const [list, setList] = useState([]);
const [isPending, startTransition] = useTransition();
const handleChange = (e) => {
const value = e.target.value;
setInput(value);
// 这里的数据更新被标记为“可延迟”
startTransition(() => {
const newList = Array.from({ length: 10000 }, (_, i) => `${value} - 项目 ${i}`);
setList(newList);
});
};
return (
<div>
<input type="text" value={input} onChange={handleChange} />
{isPending && <p>加载中...</p>}
<ul>
{list.map((item, i) => (
<li key={i}>{item}</li>
))}
</ul>
</div>
);
}