入门React:对比与Vue3的差别

645 阅读4分钟

快速入门

了解每天都会使用的80%的React概念,同时对比Vue(这里主要是Vue3),比较它们的差别

创建和嵌套组件

  • React应用程序是由组件组成的。
  • 组件小到一个按钮,大到整个页面
  • 组件必须以大写字母开头,而HTML标签必须是小写字母

创建组件

React组件是返回标签的JS函数:

function MyButton(){
  return (
    <button>按钮</button>
  )
}

对比Vue组件:

<template>
   <button>按钮</button>
</template>
  • React用中括号()包裹html标签,而Vue用<template> 包裹
  • React组件是.js/.jsx文件,Vue组件是.vue文件
  • React组件是JS函数,Vue组件本质上也会编译为渲染函数

嵌套组件

function MyButton() {
  return (
    <button>按钮</button>
  );
}

// export default 关键字指定了文件中的主要组件
export default function MyApp() {
  return (
    <div>
      <h1>Welcome to my app</h1>
      <MyButton />
    </div>
  );
}

对比Vue:

<template>
    <div>
      <h1>Welcome to my app</h1>
      <MyButton />
    </div>
</template>
<script setup>
import MyButton from './MyButton'
</script>

使用JSX编写标签

  • React的标签语法称为JSX,是可选的。但大多数React项目会使用JSX,主要是方便
  • JSX比HTML更严格
    • 必须是闭合标签
    • 组件不能返回多个JSX标签。必须将它们包裹到一个共享的父级中,比如<div>...</div>或使用空的<>...\</>包裹
  • Vue支持JSX语法,但需要Babel的插件来转换

添加样式

  • 在 React 中,你可以使用 className 来指定一个 CSS 的 class。它与 HTML 的 class 属性的工作方式相同
  • 然后在一个单独的CSS文件中编写CSS规则

常见的几种方法:

  1. 使用外部CSS文件

在HTML中的 标签中引入CSS文件即可

.avatar {
  border-radius: 50%;
}
<head>
  <link rel="stylesheet" href="styles.css">
</head>

React:

export default function Avatar(){
  return (
    <img className="avatar" />
  )
}

Vue:

<template>
    <img class="avatar" />
</template>

区别:指定CSS的class使用的标签属性名不一样,React使用className,Vue使用class

  1. 使用内联样式

React:

function MyComponent() {
  const style = {
    backgroundColor: 'blue',
    color: 'white',
    padding: '10px'
  };

  return <div style={style}>Hello, World!</div>;
}

Vue:

<template>
  <div :style="style">Hello, World!</div>
</template>

<script setup>
import { reactive } from 'vue';

const style = reactive({
      backgroundColor: 'blue',
      color: 'white',
      padding: '10px'
});
</script>
  • 两者style都接收一个样式对象
  1. 使用CSS模块

React:

import styles from './MyComponent.module.css';

function MyComponent() {
  return <div className={styles.container}>Hello, World!</div>;
}

Vue:

待补充

显示数据

React:

const user = {
  name: 'Hedy Lamarr',
  imageUrl: 'https://i.imgur.com/yXOvdOSs.jpg',
  imageSize: 90,
};

export default function Profile() {
  return (
    <>
      <h1>{user.name}</h1>
      <img
        className="avatar"
        src={user.imageUrl}
        alt={'Photo of ' + user.name}
        style={{
          width: user.imageSize,
          height: user.imageSize
        }}
      />
    </>
  );
}

Vue:

<template>
  <div>
    <h1>{{ user.name }}</h1>
    <img
      class="avatar"
      :src="user.imageUrl"
      :alt="'Photo of ' + user.name"
      :style="{ width: user.imageSize + 'px', height: user.imageSize + 'px' }"
      />
  </div>
</template>

<script>
  const user = {
    name: 'Hedy Lamarr',
    imageUrl: 'https://i.imgur.com/yXOvdOSs.jpg',
    imageSize: 90,
  };

  export default {
    data() {
      return {
        user,
      };
    },
  };
</script>

<style>
  /* styles here */
</style>
  • 在React中,大括号{}里的代码会当作JS代码执行。而在Vue中,则是双大括号{{}}包裹JS代码
  • 在标签的属性中,React的属性值依然使用{}来动态赋值。而在Vue中,需要在属性前面加冒号:标识该属性值是动态的,属性值用单引号或双引号包裹着

条件渲染

React:

<div>
  // 三元表达式
  {isLoggedIn ? (
    <AdminPanel />
  ) : (
    <LoginForm />
  )}

  // 不需要else分支,使用&&语法
   {isLoggedIn && <AdminPanel />}
</div>

Vue:

<template>
  <div>
    <AdminPanel v-if="isLoggedIn"/>
    <LoginForm v-else/>

<!--   不需要else分支,使用&&语法   -->
    <AdminPanel v-if="isLoggedIn" />
  </div>
</template>
  • 在React中,使用常规的JS语法来实现条件渲染。在Vue中,通过v-if / v-show内置指令来实现

渲染列表

React:

使用for循环和array的map方法来渲染列表

const products = [
  { title: 'Cabbage', id: 1 },
  { title: 'Garlic', id: 2 },
  { title: 'Apple', id: 3 },
];

const listItems = products.map(product =>
  <li key={product.id}>
    {product.title}
  </li>
);

return (
  <ul>{listItems}</ul>
);

Vue:

使用v-for来渲染列表

<template>
  <ul>
   <li v-for="product in products" :key="product.id">
     {{product.title}}
   </li>
  </ul>
</template>
<script setup>
import { reactive } from 'vue';
const products = reactive([
  { title: 'Cabbage', id: 1 },
  { title: 'Garlic', id: 2 },
  { title: 'Apple', id: 3 },
]);
</script>
  • 都需要通过key属性来标识唯一元素

响应事件

React:

function MyButton() {
  function handleClick() {
    alert('You clicked me!');
  }

  return (
    <button onClick={handleClick}>
      Click me
    </button>
  );
}

Vue:

<template>
  <button @click="handleClick">
      Click me
    </button>
</template>
<script setup>
 function handleClick() {
    alert('You clicked me!');
  }
</script>

更新页面

我们希望组件更新信息并展示出来。比如,计算按钮被点击的次数。

React:

给组件添加state。首先从React引入useState,在组件中声明一个state变量。从useState中获取两个变量:当前的state和更新该state的函数。

import { useState } from 'react';

function MyButton() {
  // 命名惯例:[something, setSomething]
  const [count, setCount] = useState(0);

  function handleClick() {
    setCount(count + 1);
  }

  return (
    <button onClick={handleClick}>
      点击 {count} 次
    </button>
  );
}

Vue:

从Vue引入ref或reactive,在组件中声明一个变量。该变量是一个响应式数据,直接修改变量的值,组件相应的state就会自动更新。

<template>
  <button @click="handleClick">
      点击 {{count}} 次
  </button>
</template>
<script setup>
import { ref } from "vue"

const count = ref(0)
function handleClick() {
     count.value++
}
</script>
  • React更新组件状态必须调用state的更新函数才能更新,而Vue使用ref/reactive声明的state是一个响应式数据,直接修改state就会自动更新
  • 为什么要在React使用useState和在Vue中使用ref/reactive,使用普通的变量不能更新组件吗?
    • 在React中,普通的变量不会被记住,每次渲染组件会从头开始,不会考虑之前对局部变量的任何更改。而且更改普通的变量也不会触发渲染。
    • 在Vue中,和React差不多。更改普通的变量不会触发渲染,即使组件再次渲染,数据还是原来的变量值

使用Hook

  • React
    • 以 use 开头的函数被称为 Hook。比如,useState 是 React 提供的一个内置 Hook。
    • Hook可以让你使用React的不同特性,你也可以通过组合不同的Hook来创建你自己的Hook
    • 更多内置Hook见:Built-in React Hooks – React
  • Vue
    • 在Vue中没有Hook的概念,
    • 但在Vue3中,新增的”组合式函数“的特性可以让我们利用Vue的API封装和复用有状态逻辑的函数。见:组合式函数 | Vue.js
    • “组合式函数”也是借鉴了React的Hook设计,组合式函数命名惯例也是useXXX

组件间共享数据

React:

通过向上移动state来实现组件间共享数据

import { useState } from 'react';

export default function MyApp() {
  const [count, setCount] = useState(0);

  function handleClick() {
    setCount(count + 1);
  }

  return (
    <div>
      <h1>计数器一起更新</h1>
      <MyButton count={count} onClick={handleClick} />
      <MyButton count={count} onClick={handleClick} />
    </div>
  );
}

function MyButton({ count, onClick }) {
  return (
    <button onClick={onClick}>
      点击 {count} 次
    </button>
  );
}

Vue:

MyButton.vue

<template>
  <div>
    <button @click="$emit('addCount')">
      点击 {{ count }} 次
    </button>
  </div>
</template>

<script>
  export default {
   props:['count'],
  };
</script>

App.vue

<template>
  <div>
    <h1>计数器一起更新</h1>
    <MyButton :count="count" @add-count="handleClick"/>
    <MyButton :count="count" @add-count="handleClick" />
  </div>
</template>

<script setup>
  import { ref } from 'vue';
  import MyButton from './MyButton.vue'
  const count = ref(0);

  function handleClick() {
    count.value++;
  }
</script>

参考