您好,登錄后才能下訂單哦!
本篇內容主要講解“vue3中的響應式原理effect怎么實現”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“vue3中的響應式原理effect怎么實現”吧!
export let activeEffect = undefined;// 當前正在執行的effect class ReactiveEffect { active = true; deps = []; // 收集effect中使用到的屬性 parent = undefined; constructor(public fn) { } run() { if (!this.active) { // 不是激活狀態 return this.fn(); } try { this.parent = activeEffect; // 當前的effect就是他的父親 activeEffect = this; // 設置成正在激活的是當前effect return this.fn(); } finally { activeEffect = this.parent; // 執行完畢后還原activeEffect this.parent = undefined; } } } export function effect(fn, options?) { const _effect = new ReactiveEffect(fn); // 創建響應式effect _effect.run(); // 讓響應式effect默認執行 }
get(target, key, receiver) { if (key === ReactiveFlags.IS_REACTIVE) { return true; } const res = Reflect.get(target, key, receiver); track(target, 'get', key); // 依賴收集 return res; }
const targetMap = new WeakMap(); // 記錄依賴關系 export function track(target, type, key) { if (activeEffect) { let depsMap = targetMap.get(target); // {對象:map} if (!depsMap) { targetMap.set(target, (depsMap = new Map())) } let dep = depsMap.get(key); if (!dep) { depsMap.set(key, (dep = new Set())) // {對象:{ 屬性 :[ dep, dep ]}} } let shouldTrack = !dep.has(activeEffect) if (shouldTrack) { dep.add(activeEffect); activeEffect.deps.push(dep); // 讓effect記住dep,這樣后續可以用于清理 } } }
將屬性和對應的effect維護成映射關系,后續屬性變化可以觸發對應的effect函數重新run
set(target, key, value, receiver) { // 等會賦值的時候可以重新觸發effect執行 let oldValue = target[key] const result = Reflect.set(target, key, value, receiver); if (oldValue !== value) { trigger(target, 'set', key, value, oldValue) } return result; }
export function trigger(target, type, key?, newValue?, oldValue?) { const depsMap = targetMap.get(target); // 獲取對應的映射表 if (!depsMap) { return } const effects = depsMap.get(key); effects && effects.forEach(effect => { if (effect !== activeEffect) effect.run(); // 防止循環 }) }
在渲染時我們要避免副作用函數產生的遺留
const state = reactive({ flag: true, name: 'jw', age: 30 }) effect(() => { // 副作用函數 (effect執行渲染了頁面) console.log('render') document.body.innerHTML = state.flag ? state.name : state.age }); setTimeout(() => { state.flag = false; setTimeout(() => { console.log('修改name,原則上不更新') state.name = 'zf' }, 1000); }, 1000)
function cleanupEffect(effect) { const { deps } = effect; // 清理effect for (let i = 0; i < deps.length; i++) { deps[i].delete(effect); } effect.deps.length = 0; } class ReactiveEffect { active = true; deps = []; // 收集effect中使用到的屬性 parent = undefined; constructor(public fn) { } run() { try { this.parent = activeEffect; // 當前的effect就是他的父親 activeEffect = this; // 設置成正在激活的是當前effect + cleanupEffect(this); return this.fn(); // 先清理在運行 } } }
這里要注意的是:觸發時會進行清理操作(清理effect),在重新進行收集(收集effect)。在循環過程中會導致死循環。
let effect = () => {}; let s = new Set([effect]) s.forEach(item=>{s.delete(effect); s.add(effect)}); // 這樣就導致死循環了
export class ReactiveEffect { stop(){ if(this.active){ cleanupEffect(this); this.active = false } } } export function effect(fn, options?) { const _effect = new ReactiveEffect(fn); _effect.run(); const runner = _effect.run.bind(_effect); runner.effect = _effect; return runner; // 返回runner }
trigger觸發時,我們可以自己決定副作用函數執行的時機、次數、及執行方式
export function effect(fn, options:any = {}) { const _effect = new ReactiveEffect(fn,options.scheduler); // 創建響應式effect // if(options){ // Object.assign(_effect,options); // 擴展屬性 // } _effect.run(); // 讓響應式effect默認執行 const runner = _effect.run.bind(_effect); runner.effect = _effect; return runner; // 返回runner } export function trigger(target, type, key?, newValue?, oldValue?) { const depsMap = targetMap.get(target); if (!depsMap) { return } let effects = depsMap.get(key); if (effects) { effects = new Set(effects); for (const effect of effects) { if (effect !== activeEffect) { if(effect.scheduler){ // 如果有調度函數則執行調度函數 effect.scheduler() }else{ effect.run(); } } } } }
get(target, key, receiver) { if (key === ReactiveFlags.IS_REACTIVE) { return true; } // 等會誰來取值就做依賴收集 const res = Reflect.get(target, key, receiver); track(target, 'get', key); if(isObject(res)){ return reactive(res); } return res; }
當取值時返回的值是對象,則返回這個對象的代理對象,從而實現深度代理
到此,相信大家對“vue3中的響應式原理effect怎么實現”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。