入门React:对比与Vue3的差别
快速入门
了解每天都会使用的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规则
常见的几种方法:
- 使用外部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
- 使用内联样式
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都接收一个样式对象
- 使用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>
参考
转载自:https://juejin.cn/post/7241086530973368379