在公司花了半小时摸鱼时间,我学会了React

前言

大家好,我是奈德丽。如果你跟我一样,一直以来在项目中只写过Vue,但又想快速上手React,也许这篇文章会帮到你,那么来看一眼我是如何学的吧

我是如何学React的

学习新语言对于很多同学来说有些头疼,但是掌握了方法,其实也不过只是依葫芦画瓢,手到擒来。下面将React与Vue做了一些简单的对比5。

1. 组件定义方式

React 组件定义

js 复制代码
// 函数组件
export default function App() {
  // 状态和逻辑
  
  return (
    // JSX 模板
  );
}

Vue 组件定义

js 复制代码
<template>
  <!-- HTML 模板 -->
</template>

<script setup lang="ts">
  // 组件逻辑
</script>

<style scoped>
  /* 组件样式 */
</style>

2. 响应式数据详细对比

React 管理响应式数据

js 复制代码
// 使用 useState 创建状态
const [list, setList] = useState(toDolist);
const [inputVal, setInputVal] = useState("");

// 更新状态
setList(newList);
setInputVal("");

特点:

  • 状态更新是异步的
  • 状态更新会触发组件重新渲染
  • 每次渲染都会重新执行整个函数组件
  • 状态是不可变的,需要创建新对象/数组来更新

Vue管理响应式数据

js 复制代码
<script setup>
// 使用 ref 创建响应式状态
const list = ref(toDolist);
const inputVal = ref('');

// 更新状态
list.value = newList;
inputVal.value = '';
</script>

特点:

  • 基于 Proxy 的响应式系统
  • 只有依赖变化的部分会重新渲染
  • 可以直接修改 .value 属性
  • 支持深层响应式

3. 引用和持久化值

React 的 useRef

js 复制代码
const curId = useRef(list.length + 1);
const inputRef = useRef(null);

// 访问和修改
curId.current++;
inputRef.current?.focus();

特点:

  • 在组件重新渲染时保持值不变
  • 修改 .current 不会触发重新渲染
  • 可以引用 DOM 元素
js 复制代码
<script setup>
const curId = ref(list.value.length + 1);
const inputRef = ref(null);

// 访问和修改
curId.value++;
inputRef.value?.focus();
</script>

特点:

  • 在 Vue 中,ref 既可以用于响应式数据,也可以引用 DOM 元素
  • 修改 .value 会触发依赖更新
  • 通过 ref="inputRef" 绑定到模板元素

4. 模板语法对比

React JSX

js 复制代码
return (
  <>
    <input
      ref={inputRef}
      value={inputVal}
      onChange={(e) => setInputVal(e.target.value)}
    />
    <button onClick={() => handleAdd([...])}>Add</button>

    <ul>
      {list.map((item) => (
        <li key={item.id}>
          {item.title}{" "}
          <input
            type={"checkbox"}
            onChange={() => handleDelete(item.id)}
          />
        </li>
      ))}
    </ul>
  </>
);

特点:

  • 使用 JSX 语法,本质上是 JavaScript
  • 使用大括号 {} 插入表达式
  • 事件处理使用驼峰命名法 onClick
  • 列表渲染使用 map() 方法
  • 条件渲染使用 && 或三元运算符
  • 需要显式指定 key 属性

Vue 模板

js 复制代码
<template>
  <div>
    <input
      ref="inputRef"
      v-model="inputVal"
    />
    <button @click="handleAdd">Add</button>

    <ul>
      <li v-for="item in list" :key="item.id">
        {{ item.title }}
        <input
          type="checkbox"
          @change="() => handleDelete(item.id)"
        />
      </li>
    </ul>
  </div>
</template>

特点:

  • 使用基于 HTML 的模板语法
  • 使用双大括号 {{ }} 插值
  • 使用指令如 v-model 、 v-for 、 v-if
  • 事件处理使用 @ 前缀
  • 属性绑定使用 : 前缀
  • 支持双向绑定 v-model

5. 事件处理对比

React 事件处理

js 复制代码
<input onChange={(e) => setInputVal(e.target.value)} />
<button onClick={() => handleAdd([...])}>Add</button>

特点:

  • 使用驼峰命名法
  • 传递函数引用
  • 事件处理函数接收合成事件对象
  • 需要手动处理表单值更新

Vue 事件处理

js 复制代码
<input v-model="inputVal" />
<button @click="handleAdd">Add</button>

特点:

  • 使用 @ 前缀( @click 是 v-on:click 的语法糖)
  • 可以直接调用方法或内联表达式
  • v-model 提供双向绑定,简化表单处理

6. 生命周期对比

React 生命周期(Hooks)

js 复制代码
import { useEffect } from 'react';

// 组件挂载
useEffect(() => {
  inputRef.current?.focus();
}, []);

// 监听特定值变化
useEffect(() => {
  console.log('list changed:', list);
}, [list]);

// 组件卸载
useEffect(() => {
  return () => {
    console.log('component unmounted');
  };
}, []);

Vue 生命周期(组合式 API)

js 复制代码
<script setup>
import { onMounted, onUnmounted, watch } from 'vue';

// 组件挂载
onMounted(() => {
  inputRef.value?.focus();
});

// 监听特定值变化
watch(list, (newList) => {
  console.log('list changed:', newList);
});

// 组件卸载
onUnmounted(() => {
  console.log('component unmounted');
});
</script>

7.性能优化对比

React 性能优化

js 复制代码
import { memo, useCallback, useMemo } from 'react';

// 避免不必要的重新渲染
const MemoizedItem = memo(TodoItem);

// 缓存回调函数
const handleDelete = useCallback((id) => {
  // ...
}, [list]);

// 缓存计算结果
const completedItems = useMemo(() => {
  return list.filter(item => item.completed);
}, [list]);

8. 渲染机制对比

React 渲染机制

  • 使用虚拟 DOM 进行差异比较
  • 状态变化时,整个组件函数会重新执行
  • 需要手动优化避免不必要的重新渲染(memo, useMemo, useCallback)
  • 单向数据流

Vue 渲染机制

  • 也使用虚拟 DOM,但结合了依赖追踪系统
  • 精确追踪组件依赖,只更新需要更新的部分
  • 自动优化渲染,开发者通常不需要手动优化
  • 支持双向绑定

最后一步,写一个TodoList

对于Vue深度用户而言仅仅记住概念是不够的,我的建议就是直接上手敲代码,使用React做一个Todolist,通过实战,才能对React的理解更加深刻。

Vue3版本

演示链接:code.juejin.cn/pen/7493168...

js 复制代码
<template>
  <div>
    <input
      ref="inputRef"
      v-model="inputVal"
    />
    <button @click="handleAdd">
      Add
    </button>

    <ul>
      <li v-for="item in list" :key="item.id">
        {{ item.title }}
        <input
          type="checkbox"
          @change="() => handleDelete(item.id)"
        />
      </li>
    </ul>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue';

const toDolist = [
  {
    id: 1,
    title: "吃饭",
  },
  {
    id: 2,
    title: "睡觉",
  },
];

const list = ref(toDolist);
// 在Vue中,curId不会随着list的变化而重新计算
// 因为Vue使用的是基于代理(Proxy)的响应式系统,只有依赖于响应式数据的部分会更新
const curId = ref(list.value.length + 1);
const inputRef = ref(null);
const inputVal = ref('');

const handleDelete = (id: number) => {
  const newList = list.value.filter((item) => item.id !== id);
  setTimeout(() => {
    list.value = newList;
  }, 500);
};

const handleAdd = () => {
  if (inputVal.value.trim()) {
    list.value = [...list.value, { id: curId.value, title: inputVal.value }];
    curId.value++;
    inputVal.value = '';
  }
};

onMounted(() => {
  inputRef.value?.focus();
});
</script>

<style scoped>
li {
  margin: 8px 0;
}

input[type="checkbox"] {
  margin-left: 8px;
}

button {
  margin-left: 8px;
}
</style>

React版本实现

现在,让我们看看如何用React实现相同的功能:

演示链接:code.juejin.cn/pen/7493168...

tsx 复制代码
import { useState,  useRef } from "react";

const toDolist = [
  {
    id: 1,
    title: "吃饭",
  },
  {
    id: 2,
    title: "睡觉",
  },
];

export default function App() {
  const [list, setList] = useState(toDolist);

  //为什么curId在list改变的时候,值会变?
  // 当你调用 setList 更新状态时,React会重新执行整个Gallery函数组件,这意味着 let curId=list.length; 会被重新执行,curId会被重新赋值为当前list的长度。

  // 而Vue使用的是基于代理(Proxy)的响应式系统,只有依赖于响应式数据的部分会更新,而不是重新执行整个组件函数。
  // let curId=list.length;
  const curId = useRef(list.length + 1);
  const inputRef = useRef(null);
  const handleDelete = (id) => {
    const newList = list.filter((item) => item.id !== id);
    setTimeout(() => {
      setList(newList);
    }, 500);
  };
  const handleAdd = (newList) => {
    setInputVal("");

    setList(newList);
    curId.current++;
  };

  const [inputVal, setInputVal] = useState("");

  return (
    <>
      <input
        ref={inputRef}
        value={inputVal}
        onChange={(e) => setInputVal(e.target.value)}
      ></input>
      <button
        onClick={() =>
          handleAdd([...list, { id: curId.current, title: inputVal }])
        }
      >
        Add
      </button>

      <ul>
        {
         list.map((item) => {
          return (
            <li key={item.id}>
              {item.title}{" "}
              <input
                type={"checkbox"}
                onChange={() => handleDelete(item.id)}
              ></input>
            </li>
          );
        })}
      </ul>
    </>
  );
}

实现效果:

结语

以上从Vue开发一个Todolist会用到的基本知识,在React中寻找对应的实现方案的角度来入门React,读完你应该会用React开发一些简单的页面,之后我们会讲如何在React中像Vue Router一样管理url。

恩恩......懦夫的味道

相关推荐
该用户已不存在20 分钟前
这6个网站一旦知道就离不开了
前端·后端·github
Ai行者心易24 分钟前
10天!前端用coze,后端用Trae IDE+Claude Code从0开始构建到平台上线
前端·后端
东东23332 分钟前
前端开发中如何取消Promise操作
前端·javascript·promise
掘金安东尼37 分钟前
官方:什么是 Vite+?
前端·javascript·vue.js
柒崽38 分钟前
ios移动端浏览器,vh高度和页面实际高度不匹配的解决方案
前端
渣哥1 小时前
你以为 Bean 只是 new 出来?Spring BeanFactory 背后的秘密让人惊讶
javascript·后端·面试
烛阴1 小时前
为什么游戏开发者都爱 Lua?零基础快速上手指南
前端·lua
大猫会长1 小时前
tailwindcss出现could not determine executable to run
前端·tailwindcss
Moonbit1 小时前
MoonBit Pearls Vol.10:prettyprinter:使用函数组合解决结构化数据打印问题
前端·后端·程序员
533_1 小时前
[css] border 渐变
前端·css