Svelte學習筆記三:計算屬性+複雜類型更新的坑

7. 聲明(計算屬性)

在官方文檔中把(declaration)vueclassgetreactuseMemo定義的變量叫做,聲明(declaration),但是我覺得用來說他是計算屬性更好一些,類似vue,或者是class中的get方法,react中useMemo定義的變量,其原因是**我們通過定義一個根據依賴值的變化而變化的動態參數**

  1. 一個簡單的兩倍值的例子
<script>
    let count = 0;

    $: doubleCount = count * 2

    function addCount() {
        count++
    }
</script>

<div>{count} * 2 = {doubleCount}</div>
<button on:click={addCount}>+1</button>
  • 實驗效果

在這裏插入圖片描述

這裏的$ 在我的理解中完全可以作爲count改變時的一個回調函數,可以類比於react中的useEffect + useMemo,爲了驗證猜想,我們來測試一下

  1. 一個回調函數的例子
<script>
    let count = 0;

    $: doubleCount = count * 2

    function addCount() {
        count++
    }

    let callbackForCount;
    
	// 爲count添加回調 
    $: {
        console.log(`${count} is changed`)
    }

	// 爲count添加callback
    $: {
        callbackForCount = () => {
            return `現在的count是${count}`
        }
    }

</script>

<div>{count} * 2 = {doubleCount}</div>
<button on:click={addCount}>+1</button>

<div>{ callbackForCount() }</div>

  • 實驗效果

在這裏插入圖片描述

  • 文檔是這麼說的

We’re not limited to declaring reactive values — we can also run arbitrary statements reactively.

聲明任何響應值的行爲都是被允許的,我們可以運行任意響應的狀態表達式

比如我們可以聲明一個if

$: if (count >= 10) {
	alert(`count is dangerously high!`);
	count = 9;
}

這些都是被允許的

8. 複雜類型的更新問題

Because Svelte’s reactivity is triggered by assignments, using array methods like push and splice won’t automatically cause updates. For example, clicking the button doesn’t do anything.

Svelte 是通過賦值來發起數據響應的,因此對於array中的push和splice等方法來改變數組並不會被監聽到,因此不會引起頁面的重新渲染。

因此,如果當我們通過對引用類型採取非 = 號的方式進行改值,其並不會使頁面重新渲染,例如下面一個例子

<script>
  let friends = ["tom", "jack"];
  let score = {
    math: 100,
    chinese: 80
  };
  let people = {
    name: "jemmery",
    friends,
    score
  };
  let newFriend = "";

  $: numOfFriends = people.friends.length;

  function addFriends() {
    // 解決方法
    // people.friends = [...people.friends, newFriend]
    
    // 通過下面的兩種方法並不會生效
    people.friends.push(newFriend);
    // friends.push(newFriend)
    console.log(people.friends)
    newFriend = "";
  }

  function handleInput(e) {
    newFriend = e.target.value;
  }

  const changeScore = () => {
      // 這種方法並不會導致輸出的score變化,但是people.score確實發生了變化
      score.math = 30
      console.log(people.score)
      // 通過下面的方法可以使頁面進行強制渲染
      // 解決方法
      // people.score = people.score
  }
</script>

<style>

</style>

<div>
  {people.name} has {numOfFriends} friend{numOfFriends > 1 ? 's' : ''}: {people.friends.join(',')}
  <div>數學:{people.score.math}</div>
  <div>語文:{people.score.chinese}</div>
  <br />
  <input type="text" value={newFriend} on:input={handleInput} />
  <button on:click={addFriends}>增加朋友</button>
  <button on:click={changeScore}>改變分數</button>
</div>
  • 效果

在這裏插入圖片描述

我們通過這種方式進行修改參數發現並不會發生變化,其原因是隻有等號賦值 纔會導致頁面的刷新

現在我們通過代碼中標記爲解決方法的代碼來解決這個問題

  • 問題解決

在這裏插入圖片描述

  • 總結
    • 在svelte中,利用非=號的方式對引用類型進行修改會導致頁面更新監聽的失效,例如數組的splice和push方法
    • 解決辦法通過強行等號賦值,實現頁面的強制刷新
    • 第二種方法是通過…表達式對值進行賦值,也能解決這個問題
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章