适合Vue用户的React教程,你值得拥有
发表时间:2021-1-5
发布人:葵宇科技
浏览次数:71
小编日常工作中使用的是Vue,对于React只是做过简单的了解,并没有做过深入学习。趁着这个双节假期,小编决定好好学一学React,今天这篇文章就是小编在学习React之后,将React与Vue的用法做的一个对比,通过这个对比,方便使用Vue的小伙伴可以快速将Vue中的写法转换为React的写法。
插槽,在React中没找到??
在使用Vue的时候,插槽是一个特别常用的功能,通过定义插槽,可以在调用组件的时候将外部的内容传入到组件内部,显示到指定的位置。在Vue中,插槽分为默认插槽,具名插槽和作用域插槽。其实不仅仅Vue,在React中其实也有类似插槽的功能,只是名字不叫做插槽,下面我将通过举例来说明。
默认插槽
现在项目需要开发一个卡片组件,如下图所示,卡片可以指定标题,然后卡片内容可以用户自定义,这时候对于卡片内容来说,就可以使用插槽来实现,下面我们就分别使用Vue和React来实现这个功能

Vue实现
-
首先实现一个
card组件,如下代码所示复制代码{{ title }}可以看到上面我们使用了
,这个就是组件的默认插槽,在使用组件的时候,传入的内容将会被放到所在位置 -
在外部使用定义的
card组件复制代码我将被放在card组件的默认插槽里面如上代码,就可以使用组件的默认插槽将外部的内容应用到组件里面指定的位置了。
React实现
虽然在React里面没有插槽的概念,但是React里面也可以通过props.children拿到组件标签内部的子元素的,就像上面代码标签内的子元素,通过这个我们也可以实现类似Vue默认插槽的功能,一起看看代码。
-
使用
React定义Card组件import React from 'react' export interface CardProps { title: string, children: React.ReactNode } export default function(props: CardProps) { return (); } 复制代码{props.title}{/**每个组件都可以获取到 props.children。它包含组件的开始标签和结束标签之间的内容 */} {props.children}- 在外部使用
Card组件
import React from 'react' import Card from './components/Card' export default function () { return (); } 复制代码我将被放在card组件的body区域内容 - 在外部使用
具名插槽
继续以上面的Card组件为例,假如我们现在需求发生了变化,组件的title也可以使用插槽,这时候对于Vue就可以使用具名插槽了,而React也是有办法实现的哦。
Vue实现
Vue的具名插槽主要解决的是一个组件需要多个插槽的场景,其实现是为添加name属性来实现了。
- 我们就上面的需求对
card组件进行修改
{{ title }}
复制代码
card组件修改完之后,我们再去调整一下使用card组件的地方
这里是标题
我将被放在card组件的默认插槽里面
复制代码
React实现
React连插槽都没有, 更别提具名插槽了,但是没有不代表不能模拟出来。对于React的props,我们不仅仅可以传入普通的属性,还可以传入一个函数,这时候我们就可以在传入的这个函数里面返回JSX,从而就实现了具名插槽的功能。
- 对原有的
Card组件进行修改
import React from 'react'
export interface CardProps {
title?: string,
// 加入了一个renderTitle属性,属性类型是Function
renderTitle?: Function,
children: React.ReactNode
}
export default function(props: CardProps) {
const {title, renderTitle} = props
// 如果指定了renderTtile,则使用renderTitle,否则使用默认的title
let titleEl = renderTitle ? renderTitle() : {title}
return (
{titleEl}
{/**每个组件都可以获取到 props.children。它包含组件的开始标签和结束标签之间的内容 */}
{props.children}
);
}
复制代码
- 这时候就可以在外部自定义
title了
import React from 'react'
import Card from './components/Card'
export default function () {
return (
{
return 我是自定义的标题
}
}>
我将被放在card组件的body区域内容
);
}
复制代码
作用域插槽
有时让插槽内容能够访问子组件中才有的数据是很有用的,这个就是Vue提供作用域插槽的原因。我们继续使用上面的Card组件为例,现在我基于上面的卡片组件开发了一个人员信息卡片组件,用户直接使用人员信息卡片组件就可以将人员信息显示到界面中,但是在某些业务模块需要自定义人员信息显示方式,这时候我们就需要使用到作用域插槽了。
Vue实现
- 实现用户信息卡片组件,里面使用了作用域插槽
姓名: {{ userInfo.name }}
性别: {{ userInfo.sex }}
年龄: {{ userInfo.age }}
复制代码
- 在外部使用人员信息组件
- 姓名: {{ userInfo.name }}
- 年龄: {{ userInfo.age }}
复制代码
React实现
在具名插槽那一小节我们通过给组件传入了一个函数,然后在函数中返回JSX的方式来模拟了具名插槽,那么对于作用域插槽,我们依然可以使用函数的这种方式,而作用域插槽传递的参数我们可以使用给函数传参的方式来替代
-
实现人员信息卡片组件
import React, { useState } from 'react' import Card from './Card' interface UserCardProps { renderUserInfo?: Function } export interface UserInfo { name: string; age: number; sex: string; } export default function(props: UserCardProps) { const [userInfo] = useState({ name: "张三", age: 25, sex: "男", }); const content = props.renderUserInfo ? ( props.renderUserInfo(userInfo) ) : ( 姓名: {userInfo.name} 年龄: {userInfo.age} 性别: {userInfo.sex}); return{content} } 复制代码
-
在外部使用人员信息卡片组件
import React from 'react' import UserCard, { UserInfo } from "./components/UserCard"; export default function () { return (); } 复制代码{ return ( - 姓名: {userInfo.name}
Context, React中的provide/inject
通常我们在项目开发中,对于多组件之间的状态管理,在Vue中会使用到Vuex,在React中会使用到redux或者Mobx,但对于小项目来说,使用这些状态管理库就显得比较大材小用了,那么在不使用这些库的情况下,如何去完成数据管理呢?比如面试最常问的祖孙组件通信。在Vue中我们可以使用provide/inject,在React中我们可以使用Context。
假设有这样一个场景,系统现在需要提供一个换肤功能,用户可以切换皮肤,现在我们分别使用Vue和React来实现这个功能。
Vue中的provide/inject
在Vue中我们可以使用provide/inject来实现跨多级组件进行传值,就以上面所说场景为例,我们使用provide/inject来实现以下
首先,修改App.vue内容为以下内容
复制代码
然后在任意层级的子组件中像下面这样使用
复制代码
这样就可以实现theme在所有子组件中进行共享了
React中的Context
在Vue中我们使用provide/inject实现了组件跨层级传值功能,在React中也提供了类似的功能即Context,下面我们使用Context来实现相同的功能。
在项目src目录下新建context目录,添加MyContext.js文件,然后添加以下内容
import {createContext} from 'react'
// 定义 MyContext,指定默认的主题为`light`
export const MyContext = createContext({
theme: 'light'
})
复制代码
MyContext提供了一个Provider,通过Provider可以将theme共享到所有的子组件。现在我们在所有的组件的共同父组件比如App.js上面添加MyContext.Provider将theme共享出去
import { MyContext } from '@/context/MyContext';
export default function() {
const [theme, setTheme] = useState('dark')
return (
)
}
复制代码
然后这时候就可以直接在所有的子组件里面使用定义的主题theme了
import React, { useContext } from 'react' import { MyContext } from '@/context/MyContext'; export default function() { const {theme} = useContext(MyContext) return} 复制代码
没有了v-model,但也不影响使用
我们知道React和Vue都是单向数据流的,即数据的流向都是由外层向内层组件进行传递和更新的,比如下面这段React代码就是标准的单向数据流.
import React, { useState } from "react";
export default function(){
const [name] = useState('子君')
return
}
复制代码
在vue中使用v-model
如上代码,我们在通过通过value属性将外部的值传递给了input组件,这个就是一个简单的单向数据流。但是在使用Vue的时候,还有两个比较特殊的语法糖v-model和.sync,这两个语法糖可以让Vue组件拥有双向数据绑定的能力,比如下面的代码
复制代码
通过v-model,当用户修改input的值的时候,外部的name的值也将同步被修改。但这是Vue的语法糖啊,React是不支持的,所以React应该怎么办呢?这时候再想想自定义v-model,v-model实际上是通过定义value属性同时监听input事件来实现的,比如这样:
复制代码
在react寻找v-model替代方案
同理,React虽然没有v-model语法糖,但是也可以通过传入属性然后监听事件来实现数据的双向绑定。
import React, { useState } from 'react'
export default function() {
const [name, setName] = useState('子君')
const handleChange = (e) => {
setName(e.target.value)
}
return
}
复制代码
小编刚开始使用react,感觉没有v-model就显得比较麻烦,不过麻烦归麻烦,代码改写也要写。就像上文代码一样,每一个表单元素都需要监听onChange事件,越发显得麻烦了,这时候就可以考虑将多个onChange事件合并成一个,比如像下面代码这样
import React, { useState } from 'react'
export default function () {
const [name, setName] = useState('子君')
const [sex, setSex] = useState('男')
const handleChange = (e:any, method: Function) => {
method(e.target.value)
}
return
handleChange(e, setName)}>
handleChange(e, setSex)}>
}
复制代码
没有了指令,我感觉好迷茫
在Vue中我们一般绘制页面都会使用到template,template里面提供了大量的指令帮助我们完成业务开发,但是在React中使用的是JSX,并没有指令,那么我们应该怎么做呢?下面我们就将Vue中最常用的一些指令转换为JSX里面的语法(注意: 在Vue中也可以使用JSX)
v-show与v-if
在Vue中我们隐藏显示元素可以使用v-show或者v-if,当然这两者的使用场景是有所不同的,v-show是通过设置元素的display样式来显示隐藏元素的,而v-if隐藏元素是直接将元素从dom中移除掉。
-
看一下
Vue中的v-show与v-if的用法姓名:{{ name }} {{ dept }}复制代码 -
将
v-show,v-if转换为JSX中的语法在
Vue中指令是为了在template方便动态操作数据而存在的,但是到了React中我们写的是JSX,可以直接使用JS,所以指令是不需要存在的,那么上面的v-show,v-if如何在JSX中替代呢import React, { useState } from 'react' export default function() { const [showName] = useState(false) const [showDept] = useState(true) const [userInfo] = useState({ name:'子君', dept: '银河帝国' }) return ({/**模拟 v-show */} {userInfo.name} {/**模拟 v-if */} {showDept ? {userInfo.dept}: undefined}) } 复制代码
v-for
v-for在Vue中是用来遍历数据的,同时我们在使用v-for的时候需要给元素指定key,key的值一般是数据的id或者其他唯一且固定的值。不仅在Vue中,在React中也是存在key的,两者的key存在的意义基本一致,都是为了优化虚拟DOM diff算法而存在的。
-
在
Vue中使用v-for复制代码- {{ item.name }}
-
在
React中使用v-for的替代语法在
react中虽然没有v-for,但是JSX中可以直接使用JS,所以我们可以直接遍历数组import React from 'react' export default function() { const data = http://www.wxapp-union.com/[ { id: 1, name:"子君", }, { id: "2", name: "张三", }, { id: "3", name: "李四", }, ]; return () } 复制代码-
{
data.map(item => {
return
- {item.name} }) }
v-bind与v-on
v-bind在Vue中是动态绑定属性的,v-on是用于监听事件的,因为React也有属性和事件的概念,所以我们在React也能发现可替代的方式。
-
在
Vue中使用v-bind与v-on复制代码 -
在
React中寻找替代方案在
Vue中,作者将事件和属性进行了分离,但是在React中,其实事件也是属性,所以在本小节我们不仅看一下如何使用属性和事件,再了解一下如何在React中自定义事件-
开发一个
CustomInput组件import React from 'react' export interface CustomInputProps { value: string; //可以看出 onChange是一个普通的函数,也被定义到了组件的props里面了 onChange: ((value: string,event: React.ChangeEvent) => void) | undefined; } export default function(props: CustomInputProps) { function handleChange(e: React.ChangeEvent ) { // props.onChange是一个属性,也是自定义的一个事件 props.onChange && props.onChange(e.target.value, e) } return ( ) } 复制代码
-
-
使用
CustomInput组件import React, { useState } from 'react' import CustomInput from './components/CustomInput' export default function() { const [value, setValue] = useState('') function handleChange(value: string) { setValue(value) } return () } 复制代码总结
刚开始从
Vue转到React的时候,其实是有点不适应的,但是当慢慢的习惯之后,就会发现Vue和React是存在很多共性的,可以参考的去学习。当然无论Vue还是React,上手比较快,但是想深入学习还是需要下功夫的,后续小编将会对Vue和React的用法在做更深入的介绍,敬请期待。
作者:前端进击者
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。








