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