適合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,在平常工做中仍是很經常使用的,經過這種對比的學習,能夠比較好的將二者聯合在一塊兒,方便記憶。本文首發於公衆號**【前端有的玩】,學前端,面試找工做,就在【前端有的玩】**

相關文章
相關標籤/搜索