watchEffect
執(zhí)行監(jiān)聽
watchEffect比較奇特快集,它跟Vue 2的watch有所區(qū)別,它的寫法是:
watchEffect(() => {
// 執(zhí)行一些操作个初,其中必須含有響應(yīng)式變量
})
為什么感覺怪怪的院溺?watchEffect并沒有要求你聲明被監(jiān)聽的變量,而是逐虚,你在執(zhí)行體里寫哪個(gè)變量谆膳,Vue就收集、監(jiān)聽哪個(gè)變量买雾,而且可以同時(shí)監(jiān)聽多個(gè)變量漓穿,看下例:
<template>
<div>
<button @click="r++">{{ r }}</button>
<button @click="s.a++">{{ s.a }}</button>
<button @click="s.b++">{{ s.b }}</button>
<button @click="s.a++;s.b++">{{ s.a }} - {{ s.b }}</button>
</div>
</template>
<script>
import { ref, computed, watchEffect } from 'vue';
export default {
setup() {
let r = ref(10);
watchEffect(() => {
console.log(r.value);
});
let s = ref({a: 100, b: 200});
watchEffect(() => {
console.log('a:', s.value.a);
});
watchEffect(() => {
console.log('b:', s.value.b);
});
watchEffect(() => {
console.log('a - b:', s.value.a + '-' + s.value.b);
});
watchEffect(() => {
console.log('value:', s.value);
});
return {
r,s
};
},
};
</script>
可以看到:
首先器净,watchEffect是立即執(zhí)行的当凡,所以組件初始化的時(shí)候就全部執(zhí)行了一遍。
點(diǎn)擊button1浪慌,打印10权纤,很好理解乌妒。
s的傳入值是個(gè)對(duì)象,button2修改的是屬性a古掏,那么槽唾,只有監(jiān)聽屬性a的監(jiān)聽器才會(huì)有反應(yīng),只跟屬性b相關(guān)的監(jiān)聽是不會(huì)有反應(yīng)的庞萍,只監(jiān)聽s.value的監(jiān)聽器也不會(huì)有反應(yīng)钝计。點(diǎn)擊button3和button4也會(huì)印證這個(gè)結(jié)論。
在watchEffect里操作響應(yīng)式數(shù)據(jù)债沮,不會(huì)引起無(wú)限循環(huán)監(jiān)聽践付,這雖然很顯而易見永高,但是也在此說一句提针。
多個(gè)watchEffect的執(zhí)行順序是watchEffect的書寫順序。
watchEffect拿不到更新前的值饲宛,這一點(diǎn)要注意艇抠。
停止監(jiān)聽
- 自動(dòng)停止
先說watchEffect生命周期的開始久锥,是從組件的setup()函數(shù)或生命周期鉤子被調(diào)用時(shí)開始。自動(dòng)停止是在組件卸載時(shí)自動(dòng)停止絮重。
- 手動(dòng)停止
將watchEffect賦值給變量青伤,執(zhí)行這個(gè)變量即可手動(dòng)停止殴瘦。比如:
const xx = watchEffect(() => {
console.log('a:', s.value.a);
s.value.a += 10
});
// 后來(lái)某個(gè)時(shí)間執(zhí)行了:
xx(); // 停止監(jiān)聽
清除副作用
官方文檔:https://v3.cn.vuejs.org/guide/reactivity-computed-watchers.html#清除副作用
官方文檔里偶爾會(huì)蹦出來(lái)一個(gè)詞“副作用”,初學(xué)者看完一頭霧水擎厢,什么鬼副作用?英文文檔里副作用是Side Effect芬探,到底什么意思厘惦?
純函數(shù)里的副作用概念
副作用其實(shí)是一個(gè)比較生僻的概念宵蕉,最早來(lái)自于“純函數(shù)”,純函數(shù)是編程界早期的一個(gè)概念别智,具體可以看(https://zhuanlan.zhihu.com/p/139659155 和 https://juejin.cn/post/6950059795659358221)稼稿。純函數(shù)特征:
它應(yīng)始終返回相同的值让歼。不管調(diào)用該函數(shù)多少次,無(wú)論今天硬猫、明天還是將來(lái)某個(gè)時(shí)候調(diào)用它改执。
自包含(不使用全局變量)辈挂。
它不應(yīng)修改程序的狀態(tài)或引起副作用(修改全局變量)。
注意看冕香,這里就出現(xiàn)了“副作用”后豫。所以挫酿,純函數(shù)的副作用就是:
一個(gè)函數(shù)除了返回確定的值之外,還做了其他的事情惫霸,那么這個(gè)函數(shù)做的這些事情就叫做“副作用”。
比如console.log(123)
就有副作用猜丹,它返回undefined
是主作用硅卢,但是我們不需要它的主作用,它的副作用就是在控制臺(tái)打印123
脉顿,我們要的是它的副作用点寥。
再比如:
let counter = 0;
// 有副作用,副作用是把外部變量改了
incCounter() {
counter += 1;
return counter;
}
// 沒有副作用
incNumber(m) {
return m + 1;
}
React中的副作用概念
React等框架早先就在使用這個(gè)詞蔽莱,Vue從3.0開始碾褂,在文檔里出現(xiàn)這個(gè)詞历葛。
那么嘀略,在React中,是不是副作用也是這個(gè)定義呢咒程?未必帐姻∧潭危看看React是怎么說的:
你之前可能已經(jīng)在 React 組件中執(zhí)行過數(shù)據(jù)獲取、訂閱或者手動(dòng)修改過 DOM呢铆。我們統(tǒng)一把這些操作稱為“副作用”棺克,或者簡(jiǎn)稱為“作用”。
useEffect
就是一個(gè) Effect Hook娜谊,給函數(shù)組件增加了操作副作用的能力。它跟 class 組件中的componentDidMount
拇惋、componentDidUpdate
和componentWillUnmount
具有相同的用途撑帖,只不過被合并成了一個(gè) API澳眷。
例如,下面這個(gè)組件在 React 更新 DOM 后會(huì)設(shè)置一個(gè)頁(yè)面標(biāo)題:
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
// 相當(dāng)于 componentDidMount 和 componentDidUpdate:
useEffect(() => {
// 使用瀏覽器的 API 更新頁(yè)面標(biāo)題
document.title = `You clicked ${count} times`;
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
當(dāng)你調(diào)用
useEffect
時(shí)衷敌,就是在告訴 React 在完成對(duì) DOM 的更改后運(yùn)行你的“副作用”函數(shù)缴罗。由于副作用函數(shù)是在組件內(nèi)聲明的面氓,所以它們可以訪問到組件的 props 和 state蛆橡。默認(rèn)情況下,React 會(huì)在每次渲染后調(diào)用副作用函數(shù) —— 包括第一次渲染的時(shí)候呻拌。
副作用函數(shù)還可以通過返回一個(gè)函數(shù)來(lái)指定如何“清除”副作用藐握。
看完了之后垃喊,我們就知道React對(duì)于副作用的解釋:
在執(zhí)行所有業(yè)務(wù)邏輯之前,也就是組件初始化的時(shí)候抬闷,組件根據(jù)開發(fā)者的設(shè)定,由自身驅(qū)動(dòng)的第一次DOM修改评架,就是主作用纵诞。此時(shí)培遵,組件還沒有執(zhí)行任何一行邏輯代碼。
主作用之后嗡呼,組件就開始執(zhí)行用戶邏輯了南窗,這里你眼里的業(yè)務(wù)邏輯代碼郎楼,在React眼里都是副作用。
Vue 3里的副作用概念
跟React應(yīng)該是說的一個(gè)意思敌买,具體說:
所以首先了解一下“主作用”虹钮,在Vue世界里荐操,視圖層和DOM層是兩碼事珍策,盡管一些初級(jí)程序員認(rèn)為它們是一碼事。變更響應(yīng)式數(shù)據(jù)的主作用就是變更后的數(shù)據(jù)能渲染到視圖層屯耸。前端還有比這個(gè)事更重要的事嗎蹭劈?沒有吧铺韧。
副作用就是響應(yīng)式數(shù)據(jù)的變更造成的其他連鎖反應(yīng),以及后續(xù)邏輯塔逃,這些連鎖反應(yīng)都叫副作用。在藥物學(xué)里伏蚊,副作用往往是不良反應(yīng)躏吊,但是在Vue 3里并不是帐萎。上面標(biāo)題里說“清除副作用”,也并不是說因?yàn)楦弊饔檬遣涣挤磻?yīng)所以要清除凳怨,而是Vue 3提供一個(gè)方法讓你隨時(shí)可以取消副作用肤舞。
副作用主要有:
DOM更新
watchEffect
watch
computed
...
你沒看錯(cuò)均蜜,既然更新視圖層才是主作用,那么視圖層更新到DOM上在Vue眼里是副作用篙顺,而且德玫,變更響應(yīng)式數(shù)據(jù)觸發(fā)執(zhí)行computed和觸發(fā)執(zhí)行watchEffect當(dāng)然也是副作用椎麦。所以watchEffect本身就是副作用。
清除副作用是什么意思
那么官方文檔說的“清除副作用”到底在說什么琴儿?它意思是說造成,如果有些副作用是異步的雄嚣,這就意味著你可以取消它,那么Vue創(chuàng)始人就給你提供了一個(gè)方法鼓鲁,讓你優(yōu)雅的取消這些異步副作用。
比如你有一個(gè)頁(yè)碼組件尺棋,里面有5個(gè)頁(yè)碼膘螟,點(diǎn)擊就會(huì)異步請(qǐng)求數(shù)據(jù)碾局。于是我就做了一個(gè)監(jiān)聽,監(jiān)聽當(dāng)前頁(yè)碼内斯,只要有變化就ajax一次俘闯。下例是不可直接運(yùn)行的演示代碼:
let content = '';
const pageNumber = ref(1);
function onClickPageNumber(val) {
pageNumber.value = val;
}
watchEffect(() => {
ajax({pageNumber}).then(response => {
content = response.data;
})
});
現(xiàn)在問題是忽冻,如果我點(diǎn)擊的比較快,從1到5全點(diǎn)了一遍遮婶,那么會(huì)有5個(gè)ajax請(qǐng)求旗扑,最終頁(yè)面會(huì)顯示第幾頁(yè)的內(nèi)容慈省?你說第5頁(yè)?那你是假定請(qǐng)求第5頁(yè)的ajax響應(yīng)的最晚清钥,事實(shí)呢?并不一定缕坎。于是這就會(huì)導(dǎo)致錯(cuò)亂。還有一個(gè)問題匾寝,我連續(xù)快速點(diǎn)5次頁(yè)碼,等于我并不想看前4頁(yè)的內(nèi)容急凰,那么是不是前4次的請(qǐng)求都屬于帶寬浪費(fèi)抡锈?這也不好乔外。于是官方就給出了一種解決辦法:
首先,你的異步操作必須是能中止的異步操作撇簿,對(duì)于定時(shí)器來(lái)講中止定時(shí)器很容易四瘫,clearInterval之類的就可以欲逃,但對(duì)于ajax來(lái)講,需要借助ajax庫(kù)(比如axios)提供的中止ajax辦法來(lái)中止ajax∏妈荆現(xiàn)在我寫一個(gè)能直接運(yùn)行的范例演示一下中止異步操作:
我先搭建一個(gè)最簡(jiǎn)Node服務(wù)器竭望,3300端口的:
const http = require('http');
const server = http.createServer((req, res) => {
res.setHeader('Access-Control-Allow-Origin', "*");
res.setHeader('Access-Control-Allow-Credentials', true);
res.setHeader('Access-Control-Allow-Methods', 'POST, GET, PUT, DELETE, OPTIONS');
res.writeHead(200, {
'Content-Type': 'application/json'
});
});
server.listen(3300, () => {
console.log('Server is running...');
});
server.on('request', (req, res) => {
setTimeout(() => {
if (/\d.json/.test(req.url)) {
const data = {
content: '我是內(nèi)容裕菠,來(lái)自' + req.url
}
res.end(JSON.stringify(data));
}
}, Math.random() * 2000);
});
清除副作用的核心有2點(diǎn):
異步副作用要給出取消自身的辦法
watchEffect提供取消副作用的接口奴潘,也就是onInvalidate方法。
Invalidate
中文譯義是作廢掘剪,onInvalidate也就是作廢監(jiān)聽器奈虾。
<template>
<div>
<div>content: {{ content }}</div>
<button @click="pageNumber = (pageNumber++ % 5) + 1">{{ pageNumber }}</button>
</div>
</template>
<script>
import axios from 'axios';
import { ref, watchEffect } from 'vue';
export default {
setup() {
let pageNumber = ref(1);
let content = ref('');
watchEffect((onInvalidate) => {
// const CancelToken = axios.CancelToken;
// const source = CancelToken.source();
// onInvalidate(() => {
// source.cancel();
// });
axios
.get(`http://localhost:3300/${pageNumber.value}.json`, {
// cancelToken: source.token,
})
.then((response) => {
content.value = response.data.content;
})
.catch(function (err) {
if (axios.isCancel(err)) {
console.log('Request canceled', err.message);
}
});
});
return {
pageNumber,
content,
};
},
};
</script>
上面注釋掉的代碼先保持注釋掉,然后我們經(jīng)過20多次瘋狂點(diǎn)擊之后蜡塌,得到這個(gè)結(jié)果勿负,顯然,內(nèi)容錯(cuò)亂了:
現(xiàn)在我取消注釋琅摩,重新20多次瘋狂點(diǎn)擊迫吐,得到的結(jié)果就正確了:
除了最后一個(gè)請(qǐng)求志膀,上面那些請(qǐng)求有2種結(jié)局:
一種是響應(yīng)的太快鳖擒,來(lái)不及取消的請(qǐng)求,這種請(qǐng)求會(huì)返回200戳稽,不過既然它響應(yīng)太快期升,沒有任何一次后續(xù)ajax能夠來(lái)得及取消它,說明任何一次后續(xù)ajax開始之前颂郎,它就已經(jīng)結(jié)束了乓序,那么它一定會(huì)被后續(xù)某些請(qǐng)求所覆蓋坎背,所以這類請(qǐng)求的content會(huì)顯示一瞬間,然后被后續(xù)的請(qǐng)求覆蓋陨献,絕對(duì)不會(huì)比后面的請(qǐng)求還晚耿戚。
另一種就是紅色的那些被取消的請(qǐng)求阿趁,因?yàn)轫憫?yīng)的慢,所以被取消掉了皂股。
所以最終結(jié)果一定是正確的,而且節(jié)省了很多帶寬就斤,也節(jié)省了系統(tǒng)開銷蘑辑。
這就是官方說的“清除副作用”。清除定時(shí)器更簡(jiǎn)單绷旗,我不舉例了衔肢。
副作用刷新時(shí)機(jī)
官方文檔:https://v3.cn.vuejs.org/guide/reactivity-computed-watchers.html#副作用刷新時(shí)機(jī)
官方文檔里的“副作用刷新時(shí)機(jī)”更晦澀豁翎,我解釋一下。
Vue 的響應(yīng)性系統(tǒng)會(huì)緩存副作用函數(shù)邦尊,并異步地刷新它們蝉揍,這樣可以避免同一個(gè)“tick”中多個(gè)狀態(tài)改變導(dǎo)致的不必要的重復(fù)調(diào)用匙隔。
同一個(gè)“tick”的意思是,Vue的內(nèi)部機(jī)制會(huì)以最科學(xué)的計(jì)算規(guī)則將視圖刷新請(qǐng)求合并成一個(gè)一個(gè)的"tick"捍掺,每個(gè)“tick”刷新一次視圖再膳,比如a=1;b=2;
只會(huì)觸發(fā)一次視圖刷新喂柒。$nextTick的Tick就是指這個(gè)禾嫉。
繼續(xù)說熙参,比如有個(gè)watchEffect監(jiān)聽了2個(gè)變量a和b麦备,我的業(yè)務(wù)寫了a=1;b=2;
,你覺得監(jiān)聽器會(huì)調(diào)用2次黍匾?當(dāng)然不會(huì)呛梆,Vue會(huì)合并成1次去執(zhí)行填物,代碼如下,console.log只會(huì)執(zhí)行一次:
<template>
<div>
<button
@click="
r++;
s++;
"
>
{{ r }} - {{ s }}
</button>
</div>
</template>
<script>
import { ref, watchEffect } from 'vue';
export default {
setup() {
let r = ref(2);
let s = ref(10);
watchEffect(() => {
console.log(r.value, s.value);
});
return {
r,
s,
};
},
};
</script>
在核心的具體實(shí)現(xiàn)中壶笼,組件的
update
函數(shù)也是一個(gè)被偵聽的副作用雁刷。當(dāng)一個(gè)用戶定義的副作用函數(shù)進(jìn)入隊(duì)列時(shí)沛励,默認(rèn)情況下,會(huì)在所有的組件update
前執(zhí)行坤候。
所謂組件的update
函數(shù)是Vue內(nèi)置的用來(lái)更新DOM的函數(shù)企蹭,它也是副作用,上文已經(jīng)提到過徒河。這時(shí)候有一個(gè)問題顽照,就是默認(rèn)下闽寡,Vue會(huì)先執(zhí)行組件DOM update尼酿,還是先執(zhí)行監(jiān)聽器裳擎?測(cè)一下:
<template>
<div>
<button
id="aa"
@click="
r++;
s++;
"
>
{{ r }} - {{ s }}
</button>
</div>
</template>
<script>
import { ref, watchEffect } from 'vue';
export default {
setup() {
let r = ref(2);
let s = ref(10);
watchEffect(
() => {
console.log(r.value, s.value);
console.log(document.querySelector('#aa') && document.querySelector('#aa').innerText);
}
);
return {
r,
s,
};
},
};
</script>
點(diǎn)擊若干次(比如2次)按鈕句惯,得到的結(jié)果是:
為什么點(diǎn)之前按鈕的innerText打印null支救?因?yàn)槭聦?shí)就是默認(rèn)先執(zhí)行監(jiān)聽器各墨,然后更新DOM启涯,此時(shí)DOM還未生成,當(dāng)然是null黎做。
當(dāng)我第1和2次點(diǎn)擊完蒸殿,你會(huì)發(fā)現(xiàn)鸣峭,document.querySelector('#aa').innerText
獲取到的總是點(diǎn)擊之前DOM的內(nèi)容。這也說明爬骤,默認(rèn)Vue先執(zhí)行監(jiān)聽器莫换,所以取到了上一次的內(nèi)容,然后執(zhí)行組件update坷剧。
Vue 2其實(shí)也是這種機(jī)制听隐,Vue 2使用this.$nextTick()去獲取組件更新完成之后的DOM哄啄,在watchEffect里就不需要用this.$nextTick()(也沒法用)风范,有一個(gè)辦法能獲取組件更新完成之后的DOM硼婿,就是使用:
watchEffect(
() => {
/* ... */
},
{
flush: 'post'
}
)
現(xiàn)在設(shè)上flush配置項(xiàng)禽车,重新進(jìn)入組件,再看看:
沒設(shè)flush: 'post' | 設(shè)了flush: 'post' |
---|---|
image.png
|
image.png
|
所以結(jié)論是州胳,如果要操作“更新之后的DOM”栓撞,就要配置flush: 'post'碗硬。
watch
Vue 3 watch與Vue 2 watch對(duì)比
- Vue 3 watch與Vue 2的實(shí)例方法vm.$watch(也就是this.$watch)的基本用法差不多,只不過程序員大多使用watch配置項(xiàng)恩尾,可能對(duì)$watch實(shí)例方法不太熟。實(shí)例方法的一個(gè)優(yōu)勢(shì)是更靈活木人,第一個(gè)參數(shù)可以接受一個(gè)函數(shù)猎物,等于是接受了一個(gè)getter函數(shù)。
<template>
<div>
<button @click="r++">{{ r }}</button>
</div>
</template>
<script>
import { ref, watch } from 'vue';
export default {
setup() {
let r = ref(1);
let s = ref(10);
watch(
() => r.value + s.value,
(newVal, oldVal) => {
console.log(newVal, oldVal);
}
);
return {
r,
s,
};
},
};
</script>
- Vue 3 watch增加了同時(shí)監(jiān)聽多個(gè)變量的能力淘讥,用數(shù)組表達(dá)要監(jiān)聽的變量蒲列〔蟀眨回調(diào)參數(shù)是這種結(jié)構(gòu):
[newR, newS, newT], [oldR, oldS, oldT]
,不要理解成其他錯(cuò)誤的結(jié)構(gòu)抵赢。
<template>
<div>
<button @click="r++">{{ r }}</button>
</div>
</template>
<script>
import { ref, watch } from 'vue';
export default {
setup() {
let r = ref(1);
let s = ref(10);
let t = ref(100);
watch(
[r, s, t],
([newR, newS, newT], [oldR, oldS, oldT]) => {
console.log([newR, newS, newT], [oldR, oldS, oldT]);
}
);
return {
r,
};
},
};
</script>
被監(jiān)聽的變量必須是:
A watch source can only be a getter/effect function, a ref, a reactive object, or an array of these types.
也就是說铅鲤,可以是getter/effect函數(shù)、ref鹏往、Proxy以及它們的數(shù)組。絕對(duì)不可以是純對(duì)象或基本數(shù)據(jù)伊履。想要Vue 3的watch立即執(zhí)行款违,可以在watch的最后一個(gè)參數(shù)寫上
{immediate: true}
。Vue 3的深度監(jiān)聽還有沒有介褥?當(dāng)然有,而且默認(rèn)就是溢陪,無(wú)需聲明。當(dāng)然杉编,前提是深層property也是響應(yīng)式的咆霜。如果深層property無(wú)響應(yīng)式,那么即便寫上
{deep: true}
也沒用光酣。
Vue 3 watch與Vue 3 watchEffect的差異
這方面官方文檔說的還可以:
- 惰性地執(zhí)行副作用脉课,也就是說不會(huì)立即執(zhí)行一次;
- 更具體地說明應(yīng)觸發(fā)偵聽器重新運(yùn)行的狀態(tài)唱遭,這句話翻譯還是很晦澀呈驶,其實(shí)意思是說,你現(xiàn)在能一眼看出來(lái)哪個(gè)變量被監(jiān)聽订晌;
- 能訪問偵聽狀態(tài)的先前值和當(dāng)前值蚌吸,不要小看這個(gè)差別,有時(shí)候拿不到先前值就沒法進(jìn)行業(yè)務(wù)奕枢。
所以佩微,當(dāng)你不希望立即執(zhí)行一次監(jiān)聽器,或者需要拿到先前值谷浅,或者想明確表明哪些變量被監(jiān)聽了奶卓,就用watch。
其他差異有:
- 如果監(jiān)聽一個(gè)Proxy變量p,它的內(nèi)部值結(jié)構(gòu)是
{a: {b: {c: 2}}}
或{a: {b: {c: {d: 3}}}}
盏浙,我打算監(jiān)聽p.a.b.c,那么:
watchEffect | watch且p.a.b.c是基本類型 | watch且p.a.b.c是引用類型 |
---|---|---|
必須監(jiān)聽p.a.b.c自身 | 必須監(jiān)聽p.a.b.c的任意一級(jí)上級(jí)property | 監(jiān)聽p.a.b.c自身和任意上級(jí)property均可 |
- 如果監(jiān)聽ref竹海,跟上面類似斋配,只是有2個(gè)注意事項(xiàng):一是p后面不要忘記加.value孵稽,二是所謂“p.value.a.b.c的任意上級(jí)property”最高只允許到
p.value
,不能到p
园细。
Vue 3 watch與Vue 3 watchEffect的共性
官方說接校,watch也有停止偵聽狮崩,清除副作用睦柴、副作用刷新時(shí)機(jī)和偵聽器調(diào)試行為毡熏。簡(jiǎn)單舉例:
- watch停止監(jiān)聽:
停止監(jiān)聽watch很簡(jiǎn)單痢法,watch的時(shí)候就必須賦值給一個(gè)變量,這時(shí)候就開始監(jiān)聽蘸炸。想停止監(jiān)聽就把這個(gè)變量當(dāng)函數(shù)執(zhí)行一下尖奔。
<template>
<div>
<button @click="r++">{{ r }}</button>
<button @click="s()">stop</button>
</div>
</template>
<script>
import { ref, watch } from 'vue';
export default {
setup() {
let r = ref(2);
let s = watch(r, () => {
console.log(r.value);
});
return {
r,
s,
};
},
};
</script>
- watch清除副作用:
<template>
<div>
<div>content: {{ content }}</div>
<button @click="pageNumber = (pageNumber++ % 5) + 1">{{ pageNumber }}</button>
</div>
</template>
<script>
import axios from 'axios';
import { ref, watch } from 'vue';
export default {
setup() {
let pageNumber = ref(1);
let content = ref('');
watch(pageNumber, (newVal, oldVal, onInvalidate) => {
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
onInvalidate(() => {
source.cancel();
});
axios
.get(`http://localhost:3300/${pageNumber.value}.json`, {
cancelToken: source.token,
})
.then((response) => {
content.value = response.data.content;
})
.catch(function (err) {
if (axios.isCancel(err)) {
console.log('Request canceled', err.message);
}
});
});
return {
pageNumber,
content,
};
},
};
</script>
- 調(diào)整副作用刷新時(shí)機(jī)提茁,可以嘗試注釋flush: 'post',作為對(duì)比:
<template>
<div>
<button
id="aa"
@click="
r++;
s++;
"
>
{{ r }} - {{ s }}
</button>
</div>
</template>
<script>
import { ref, watch } from 'vue';
export default {
setup() {
let r = ref(2);
let s = ref(10);
watch(r,
() => {
console.log(r.value, s.value);
console.log(document.querySelector('#aa') && document.querySelector('#aa').innerText);
},
{
flush: 'post'
}
);
return {
r,
s,
};
},
};
</script>
computed
Vue 3跟Vue 2的computed的差別在于稀拐,Vue 2是所有計(jì)算屬性都是根對(duì)象的屬性,Vue 3是計(jì)算屬性都是獨(dú)立變量铲咨,其他區(qū)別很小,就不細(xì)說了坯苹。
Vue 3 computed特點(diǎn):
computed默認(rèn)接收getter函數(shù)摇天,也可以接收一個(gè)對(duì)象,對(duì)象里有g(shù)et和set方法为鳄。set方法接收一個(gè)val參數(shù)腕让。初學(xué)者可能會(huì)忘記寫getter函數(shù),只寫計(jì)算表達(dá)式偏形,要注意這點(diǎn)。
computed一定返回ref對(duì)象队橙,所以并不需要在計(jì)算函數(shù)里給返回值添加響應(yīng)式萨惑,這屬于畫蛇添足。