在公司花了半小时摸鱼时间,我学会了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。

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

相关推荐
白兰地空瓶几秒前
🚀 10 分钟吃透 CSS position 定位!从底层原理到避坑实战,搞定所有布局难题
前端·css
T___T12 分钟前
Ajax 数据请求详解与实战
javascript·面试
onthewaying20 分钟前
在Android平台上使用Three.js优雅的加载3D模型
android·前端·three.js
冴羽26 分钟前
能让 GitHub 删除泄露的苹果源码还有 8000 多个相关仓库的 DMCA 是什么?
前端·javascript·react.js
悟能不能悟28 分钟前
jsp怎么拿到url参数
java·前端·javascript
程序猿小蒜42 分钟前
基于SpringBoot的企业资产管理系统开发与设计
java·前端·spring boot·后端·spring
Mapmost1 小时前
零代码+三维仿真!实现自然灾害的可视化模拟与精准预警
前端
程序猿_极客1 小时前
JavaScript 的 Web APIs 入门到实战全总结(day7):从数据处理到交互落地的全链路实战(附实战案例代码)
开发语言·前端·javascript·交互·web apis 入门到实战
suzumiyahr1 小时前
用awesome-digital-human-live2d创建属于自己的数字人
前端·人工智能·后端
萧曵 丶1 小时前
Python 字符串、列表、元组、字典、集合常用函数
开发语言·前端·python