适合Vue用户的React教程,你值得拥有(二)

上周小编我写了 适合Vue用户的React教程,你值得拥有,获得了小伙伴们的一致好评,今天这篇文章是这一系列的第二篇文章。今年的9月18日是九一八事变89周年,同时在这一天,Vue3.0正式版发布了。相信不少小伙伴已经看过了Vue3.0相关的不少文章了。今天这篇文章将会对Vue2,Vue3,React的一些用法进行对比,方便小伙伴们学习。javascript

数据data,在react中叫state

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

Vue2.0中的用法

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

<template>
  <div>{{ name }}</div>
</template>
<script> export default { data() { return { name: '子君', gzh: '前端有的玩' } } } </script>
复制代码

经过上面的代码咱们能够看到data是一个函数,而后函数中返回了一个对象,那么为何data是一个函数呢?好比咱们有时候也会在App.vue文件中看到data不是函数的状况。vue

<template>  
	<div id="app">
    <router-view />
  </div>
</template>
<script> export default { data:{ name: '子君', sex: '男' } } </script>
复制代码

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

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

Vue3中的用法

Vue3中,咱们依然能够像Vue2那样去使用data,固然Vue3提供了新的Composition API,在后续文章中,若是没有特殊说明,咱们提到Vue3就默认指的是使用Composition API面试

Composition API提供了响应式API,分别是refreactive,经过这两个API能够生成响应式的数据api

基础用法
<template>
  <div class="home">
    <div>姓名:{{ state.name }}</div>
    <div>公众号:{{ state.gzh }}</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: "子君", gzh: "前端有的玩" }); 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.gzh }}</div>
    <div>统计:{{ count }}</div>
  </div>
</template>

<script lang="ts"> import { defineComponent, reactive, ref } from "vue"; export default defineComponent({ setup() { const state = reactive({ name: "子君", gzh: "前端有的玩" }); const count = ref(0); function handleClick() { state.name = "张三"; count.value++; } return { state, count, handleClick }; } }); </script>

复制代码

如上代码所示:markdown

  1. 对于reactive声明的数据

    对于reactive,咱们能够经过state.name来获取数据,而后经过state.name='张三'来修改数据

  2. 对于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事件以外,还能够经过vuewatch来监听关键字的变化

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]) => {
  
})
复制代码
  1. 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来模拟的,固然若是有小伙伴知道如何模拟,麻烦下方评论区告诉我,谢谢。

总结

前端技术发展突飞猛进,我表示已经学不动了,但是不学怎么赚钱吃饭,因此仍是要学。做为前端主流三大框架之二的VueReact,在平常工做中仍是很经常使用的,经过这种对比的学习,能够比较好的将二者联合在一块儿,方便记忆。本文首发于公众号**【前端有的玩】,学前端,面试找工做,就在【前端有的玩】**

相关文章
相关标签/搜索