返回博客列表

React语法学习

2026-01-29
6 min read
react

认识 React 的设计理念 以函数为中心,声明式 UI,组件树结构,单向数据流 与 Vue 对比:Vue 更“魔法”(响应式追踪),React 更“显式” 场景对比 依赖收集(Vue 的响应式 vs React 的 state) vue react 父组件触发子组件 vue react 子组件触发父组件事件(事件向上传递) vue react watch(监听变化) vue react 样式定义...

认识 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

vue
<Child ref="childRef" />
<script setup>
const childRef = ref(null)
function triggerChild() {
  childRef.value.sayHi()
}
</script>

react

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

vue
<Child @custom-event="handleEvent" />

// Child
emit('custom-event', data)

react

react
function Child({ onCustomEvent }) {
  return <button onClick={() => onCustomEvent('Hello')}>触发父组件</button>
}

function Parent() {
  function handleEvent(data) {
    alert(data)
  }
  return <Child onCustomEvent={handleEvent} />
}

watch(监听变化)

vue

vue
watch(() => state.name, (newVal, oldVal) => { ... })

react

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

vue
<template>
  <div :class="{ active: isActive }" :style="{ color: color }">Text</div>
</template>
<script setup>
const isActive = ref(true)
const color = ref('red')
</script>

react

react
function Demo() {
  const [isActive, setIsActive] = useState(true)
  const color = 'red'

  return (
    <div
      className={isActive ? 'active' : ''}
      style={{ color: color }}
    >
      Text
    </div>
  )
}

上下文

vue

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
AlgorithmContext.ts
import {createContext} from 'react';

interface ThemeContextType {
    dark: boolean;
    switchTheme: () => void;
}

export const AlgorithmContext = createContext<ThemeContextType>({
    dark: false,
    switchTheme: () => {},
});
main.tsx
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>
    )
}
ChatHeader.txs
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 对比梳理(便于理解)

特性VueReact
模板语法模板字符串JSX(更灵活的 JS)
数据响应式自动收集依赖显式设置 useStateuseEffect
事件绑定@click="fn"onClick={fn}
组件通信props / emitprops / 回调函数
生命周期created, mounteduseEffect

useState

在 vue 中回自动收集依赖,但是在 react 中是没有的,要使用 useState

// 第一个参数是数据,第二个是赋值
const [count, setCount] = useState(0);

useMemo

useMemo 用来 缓存计算结果,避免不必要的重复计算。

就像 Vue 中的 computed 属性,用于缓存函数返回值。

🧩 对比:Vue computed vs React useMemo

特性Vue computedReact 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 / piniacontext / redux / zustand

useTransition

useTransition 是 React 的并发特性之一,主要用于控制「非紧急更新」,让 UI 更加流畅。

js
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>
  );
}
返回博客列表
最后更新于 2026-01-29
想法或问题?在 GitHub Issue 下方参与讨论
去评论