目录

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

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

本文是转载文章,点击查看原文
如有侵权,请联系 xyy@jishuzhan.net 删除
相关推荐
BillKu1 小时前
Vue3 + TypeScript中provide和inject的用法示例
javascript·vue.js·typescript
培根芝士1 小时前
Electron打包支持多语言
前端·javascript·electron
Baoing_2 小时前
Next.js项目生成sitemap.xml站点地图
xml·开发语言·javascript
mr_cmx2 小时前
Nodejs数据库单一连接模式和连接池模式的概述及写法
前端·数据库·node.js
东部欧安时2 小时前
研一自救指南 - 07. CSS面向面试学习
前端·css
沉默是金~2 小时前
Vue+Notification 自定义消息通知组件 支持数据分页 实时更新
javascript·vue.js·elementui
涵信2 小时前
第十二节:原理深挖-React Fiber架构核心思想
前端·react.js·架构
在下千玦2 小时前
#去除知乎中“盐选”付费故事
javascript
ohMyGod_1232 小时前
React-useRef
前端·javascript·react.js
每一天,每一步2 小时前
AI语音助手 React 组件使用js-audio-recorder实现,将获取到的语音转成base64发送给后端,后端接口返回文本内容
前端·javascript·react.js