用React.js写法改写Vue写法的教程(一)

目录
文章目录隐藏
  1. 数据 data,在 react 中叫 state
  2. 侦听器 watch
  3. 计算属性,在 React 中我也找到的踪迹
  4. 结语

用 React.js 写法改写 Vue 写法的教程(一)

我在日常工作中使用的最多的是 Vue,对于 React 只是做过简单的了解,并没有做过深入学习。最近工作不算太忙,于是乎决定好好学一学 React,今天这篇文章就是我在学习 React 之后,将 React 与 Vue 的用法做的一个对比,通过这个对比,方便使用 Vue 的小伙伴可以快速将 Vue 中的写法转换为 React 的写法。好了,废话不多说,一起看看吧!

数据 data,在 react 中叫 state

熟悉vue的小伙伴一定对Vue中的data不会感到陌生的,反正天天写Bug的时候都要用,但是对于data来说,在Vue2.0,Vue3.0,React中用法是不同的,我们下面依次举例说明。

Vue2.0 中的用法

如下代码是一个比较简单的Vue2.0data用法

<template>
  <div>{{ name }}</div>
</template>
<script>
export default {
  data() {
    return {
      name: '码云笔记',
      mybj: 'mybj123.com'
    }
  }
}
</script>

通过上面的代码我们可以看到data是一个函数,然后函数中返回了一个对象,那么为什么data是一个函数呢?比如我们有时候也会在App.vue文件中看到data不是函数的情况。

<template>
    <div id="app">
    <router-view />
  </div>
</template>
<script>
export default {
  data:{
    name: '码云笔记',
    sex: '男'
  }
}
</script>

那么为什么我们在普通组件里面还要将data声明为函数呢?Vue 官网是这样解释的:当一个组件被定义,data 必须声明为返回一个初始数据对象的函数,因为组件可能被用来创建多个实例。如果 data 仍然是一个纯粹的对象,则所有的实例将共享引用同一个数据对象!通过提供 data 函数,每次创建一个新实例后,我们能够调用 data 函数,从而返回初始数据的一个全新副本数据对象。

App.vue可以将data声明为一个普通对象是因为整个系统中App.vue只会被使用到一次,所以不存在上述的问题。

Vue3 中的用法

Vue3中,我们依然可以像Vue2那样去使用data,当然Vue3提供了新的Composition API,在后续文章中,如果没有特殊说明,我们提到Vue3就默认指的是使用Composition API

Composition API提供了响应式API,分别是refreactive,通过这两个API可以生成响应式的数据

基础用法

<template>
  <div class="home">
    <div>姓名:{{ state.name }}</div>
    <div>域名:{{ state.mybj }}</div>
    <div>统计:{{ count }}</div>
  </div>
</template>

<script lang="ts">
import { defineComponent, reactive, ref } from "vue";

export default defineComponent({
  name: "Home",
  setup() {
    const state = reactive({
      name: "码云笔记",
      mybj: "mybj123.com"
    });
    const count = ref(0);
    return {
      state,
      count
    };
  }
});
</script>

响应数据修改

Vue2.0中,我们修改data的方式一般会使用this.name = '张三'这种赋值的方式,但是对于Composition API中因为提供了两种api,所以用法稍有区别

<template>
  <div class="home" @click="handleClick">
    <div>姓名:{{ state.name }}</div>
    <div>域名:{{ state.mybj }}</div>
    <div>统计:{{ count }}</div>
  </div>
</template>

<script lang="ts">
import { defineComponent, reactive, ref } from "vue";

export default defineComponent({
  setup() {
    const state = reactive({
      name: "码云笔记",
      mybj: "mybj123.com"
    });
    
    const count = ref(0);
    
    function handleClick() {
      state.name = "张三";
      count.value++;
    }
    
    return {
      state,
      count,
      handleClick
    };
  }
});
</script>

如上代码所示:

  • 对于reactive声明的数据对于reactive,我们可以通过state.name来获取数据,然后通过state.name='张三'来修改数据
  • 对于ref声明的数据对于ref声明的数据,ref接受一个参数值并返回一个响应式且可改变的 ref 对象。ref 对象拥有一个指向内部值的单一属性 .value。所以我们在代码中获取ref对象的数据需要使用count.value的方式,修改值的方式也需要通过count.value++的方式。但是这里有一个特殊的点就是在template,ref对象会自动解套,意思就是对于<div>统计:{{ count }}</div>,代码里面可以直接使用count,而不需要写成count.valueVue自己就会将其解套为count.value

React 中的用法

React16.8新增了Hook特性,现在许多团队已经大规模使用了,所以本文的内容更多的是以Hook为主。

Vue3.0中提供了Composition API,其实这个和Reacthook用法是很相似的,接下来我们将上文中我们写的Vue3.0代码修改为React版本

import React, { useState } from 'react'

export default function() {
  // useState 传入要初始化的状态数据,然后会返回一个数组
  // 数组第一项为声明的数据,而第二个参数是一个方法,用于调用
  // 修改数据
 const [name, setName] =  useState('码云笔记')
 const [gzh] = useState('码云笔记')

 function handleClick() {
   // 在 react 修改数据需要调用 useState 返回的方法
   setName('张三')
 }

  return (
    <div onClick={handleClick}>
      <div>姓名:{name}</div>
      <div>公众号: {gzh}</div>
    </div>
  );
}

在这段代码中我们使用到了useState声明了一个state变量,useState返回的值是一个数组,然后我们通过数组解构获取到了两个变量, const [name, setName] = useState('码云笔记'), 其中name对应声明的state变量,而setName是一个函数,调用setName可以修改变量的值,比如setName('张三'),这时候name的值就会变成了张三

侦听器 watch

我在平常开发中是比较常用watch的,使用watch可以去监听数据的变化,然后在变化之后做一系列的操作。比如有一个列表页,我们希望用户在输入搜索关键字的时候,可以自动触发搜索。此时除了监听输入框的input事件之外,还可以通过 vue 的watch来监听关键字的变化

Vue2.0 中的写法

在 vue2.0 中,watch常用的写法包含了两种,下面我们分别使用不同的写法来进行上述功能的实现

1.常规实现

<template>
  <div>
    <div>
      <span>搜索</span>
      <input v-model="searchValue" />
    </div>
    <!--列表,代码省略-->
  </div>
</template>
<script>
export default {
  data() {
    return {
      searchValue: ''
    }
  },
  watch: {
    // 在值发生变化之后,重新加载数据
    searchValue(newValue, oldValue) {
      // 判断搜索
      if (newValue !== oldValue) {
        // 在这里处理搜索逻辑
      }
    }
  }
}
</script>

2.使用$watch 实现

<template>
  <div>
    <div>
      <span>搜索</span>
      <input v-model="searchValue" />
    </div>
    <!--列表,代码省略-->
  </div>
</template>
<script>
export default {
  data() {
    return {
      searchValue: ''
    }
  },
  created() {
    // $watch 会返回一个 unwatch 函数,如果需求上需要在某些场景取消 watch,可以执行`unwatch`
    const unwatch = this.$watch('searchValue', (newValue, oldValue) => {
      // 判断搜索
      if (newValue !== oldValue) {
        // 在这里处理搜索逻辑
      }
    })
  }
}
</script>

在调用$watch的时候,会有一个返回值unwatch,然后如果需要取消 watch 监听,我们可以通过调用unwatch来进行,比如有一个表单,表单上面的保存按钮平常是置灰的,但是假如用户对表单进行了修改,就需要将表单的置灰状态修改为启用状态。但是如果表单已经启用了,就没必要继续watch了,这时候就需要使用unwatch

Vue3.0 中的写法

Vue3.0中除了Vue2.0中的写法外,还在Composition API提供了watchwatchEffect两个API,用于监听数据的变化,下面我们将上面搜索分别使用watchwatchEffect来实现

1.watch 实现方式

<template>
  <div>
    <span>搜索</span>
    <input v-model="state.searchValue" />
  </div>
</template>

<script lang="ts">
import { defineComponent, reactive, watch } from "vue";

export default defineComponent({
  setup() {
    const state = reactive({
      searchValue: ""
    });
    // 通过 watch 来监听 searchValue 的变化
    const unwatch = watch(
      () => state.searchValue,
      (value, oldValue) => {
        if (value !== oldValue) {
          // 在这里处理搜索逻辑
        }
      }
    );
    return {
      state
    };
  }
});
</script>

watch APIVue2.0中的this.$watch用法基本是一致的,包括使用的参数等,同时watch API返回了unwatch函数用于取消watch

同时watch还可以侦听多个属性的变化,就像下面这样

watch([a,b,c], ([a,b,c],[oldA,oldB,oldC]) => {

})

2.watchEffect 实现

watchEffect参数是一个函数,在代码执行时,会立即执行watchEffect传入的函数,然后响应式追踪其依赖,并在其中某些依赖发生变化时重新运行该函数。我们将上述搜索代码使用watchEffect来实现。

export default defineComponent({
  setup() {
    const state = reactive({
      searchValue: ""
    });
    // 加载数据
    function loadData(searchValue){
      
    }
    // 通过 watchEffect 来监听 searchValue 的变化
    const unwatch = watchEffect(() => {
      // 当代码执行到 watchEffect 时,会立即调用此函数,同时会收集到存在
      //`state.searchValue`的依赖,然后当`state.searchValue`发生
      //变化时会在此调用 watchEffect,已实现数据监听
      loadData(state.searchValue)
    });
    return {
      state
    };
  }
})

React 中的写法

React中与watch比较相似的功能是Effect Hook,使用它可以让你在函数组件中执行副作用操作,先来看一下代码:

import React, { useEffect, useState } from 'react'

export default function() {
  // useState 传入要初始化的状态数据,然后会返回一个数组
  // 数组第一项为声明的数据,而第二个参数是一个方法,用于调用
  // 修改数据
 const [searchValue, setSearchValue] =  useState('')

 function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
   // 在 react 修改数据需要调用 useState 返回的方法
   setSearchValue(e.target.value);
 }

 // useEffect 接受两个参数,第一个是回调函数,第二个是要监听变化的属性,是一个数组
 useEffect(() => {
   // 当代码首次调用 useEffect 会进入这个回调函数,然后
  // 当 serchValue 发生变化时,会再次进入到这里
  console.log(111)
 },[searchValue])
  return (
    <div>
      <input value={searchValue} onChange={handleChange}></input>
      
    </div>
  );
}

如上代码我们使用useEffect来监听searchValue的变化,然后触发新的逻辑,但是看到上面代码,我们并没有发现取消effect的方法,那么如何取消呢?

useEffect第二个参数是一个数组,通过给数组传入要监听的变量来实现数据监听,但是却没有办法去取消这个监听,所以我们需要曲线救国,就像下面代码这样:

 const [isWatch] = useState(true)

 useEffect(() => {
  // 通过 isWatch 来判断是否进行监听逻辑变化   
  if(isWatch) {
    // 监听数据变化
    console.log(searchValue)
  }
 },[isWatch, searchValue])

计算属性,在 React 中我也找到的踪迹

Vue中的计算属性,相信大家都很熟悉,通常我们会使用计算属性来对template中的复杂逻辑计算进行简化,比如许多英文网站输入用户名的时候会输入firstNamelastName,然后在界面上面又会将firstNamelastName连在一起显示,这时候就可以使用到了计算属性对显示进行处理

Vue2.0 中的写法

<template>
  <div>
    <div>
      <label>firstName</label>
      <input v-model="firstName" />
      <label>lastName</label>
      <input v-model="lastName" />
    </div>
    <div>用户名:{{ name }}</div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      firstName: '',
      lastName: ''
    }
  },
  computed: {
    name() {
      return this.firstName + '·' + this.lastName
    }
  }
}
</script>

Vue3.0 中的写法

Vue3.0Composition API也提供了computed API,用于生成计算属性,用法与Vue2.0用法基本是一致的

import { computed, defineComponent, reactive } from "vue";

export default defineComponent({
  setup() {
    const state = reactive({
      firstName: "",
      lastName: ""
    });
    const name = computed(() => state.firstName + "·" + state.lastName);
    return {
      state,
      name
    };
  }
});

React 中的写法

在说到在React中模拟计算属性之前,我们先要了解一些React Hook的规则。

  1. 只能在最顶层使用Hook
  2. 只能在React函数中调用Hook

当我们在React函数中使用useState之后,如果我们通过setState修改了state,那么这时候react会做什么呢?React会将这个函数式组件重新执行一遍,但是对于里面的useState,useEffect等等不会重新初始化,而是使用已经记录的状态进行处理。那么React是怎么知道哪个state对应哪个useState呢?答案是React靠的是Hook调用的顺序。所以我们不能在非顶层比如if里面使用Hook

同时呢?因为state的变化会引起整个函数重新执行,那么假如我们在代码里面写了这样一段逻辑

const [firstName, setFirstName] = useState('')
const [lastName, setLastName ] = useState('')
const [other,setOther] = useState('')

// 使用 useMemo 可以模仿 Vue 中的计算属性
const name = firstName + "·" + lastName;

上面代码里面我们的name是通过firstNamelastName计算而来的,那么当firstName或者lastName发生变化时,都会重新计算name,这个逻辑是正确的。但是实际上other如果发生了变化,也会导致name重新计算,这是我们不愿意看到的。假如name的计算逻辑很复杂,那么就会引起不必要的性能开支。所以React提供了useMemo,用于避免非相关属性变化引起计算逻辑发生变化,而我们正好可以利用useMemo来模拟计算属性,如下代码:

import React, {  useMemo, useState } from 'react'

export default function() {
  const [firstName, setFirstName] = useState('')
  const [lastName, setLastName ] = useState('')

  // 使用 useMemo 可以模仿 Vue 中的计算属性,当 firstName 与`lastName`任何一个发生变化
  //都会触发`name`重新计算,但是对于其他属性变化,并不会引起重新计算
  const name = useMemo(() => firstName + '·' + lastName,[firstName,lastName])

  const handleChange = (method: Function, e: React.ChangeEvent<HTMLInputElement> ) => {
    method(e.target.value)
  }

  return (
    <div>
      <div>
        <label>firstName</label>
        <input
          value={firstName}
          onChange={(e) => handleChange(setFirstName, e)}
        />
        <label>lastName</label>
        <input
          value={lastName}
          onChange={(e) => handleChange(setLastName, e)}
        />
      </div>
      <div>用户名:{name}</div>
    </div>
  );
}

但是呢,在Vue中计算属性既可以get,也可以set,这一点我们是无法使用useMemo来模拟的,当然如果有小伙伴知道如何模拟,麻烦下方评论区告诉我,谢谢。

结语

前端技术发展日新月异,我表示已经学不动了,可是不学怎么赚钱吃饭,所以还是要学。作为前端主流三大框架之二的 Vue 和 React,在日常工作中还是很常用的,通过这种对比的学习,可以比较好的将两者联合在一起,方便记忆。

「点点赞赏,手留余香」

0

给作者打赏,鼓励TA抓紧创作!

微信微信 支付宝支付宝

还没有人赞赏,快来当第一个赞赏的人吧!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。
码云笔记 » 用React.js写法改写Vue写法的教程(一)

发表回复