diff --git a/src/component/setup/index.js b/src/component/setup/index.js index 10462b24..7c36e74b 100644 --- a/src/component/setup/index.js +++ b/src/component/setup/index.js @@ -48,6 +48,11 @@ export default function (component, config) { // // setup computed if (config.computed) setupComputed(component, config.computed) + // // setup computedThisRefVars + if (config.computedThisRefVars) { + component[symbols.computedThisRefVars] = config.computedThisRefVars + } + // // setup watchers if (config.watch) setupWatch(component, config.watch) diff --git a/src/lib/codegenerator/generator.js b/src/lib/codegenerator/generator.js index 2390137f..c805131a 100644 --- a/src/lib/codegenerator/generator.js +++ b/src/lib/codegenerator/generator.js @@ -35,6 +35,7 @@ export default function (templateObject = { children: [] }, devMode = false) { 'let inSlot = false', 'let slotChildCounter = 0', 'let cmps = []', + 'let trackingKeys = []', ], effectsCode: [], cleanupCode: [ @@ -622,8 +623,13 @@ const generateForLoopCode = function (templateObject, parent) { } component[Symbol.for('effects')].push(eff${forStartCounter}) + trackingKeys = ['${effectKey}', ${effectKeys.join(',')}] - effect(eff${forStartCounter}, ['${effectKey}', ${effectKeys.join(',')}]) + if (component[Symbol.for('computedKeys')] && component[Symbol.for('computedKeys')].indexOf('${effectKey}') !== -1) { + trackingKeys.push(...component[Symbol.for('computedThisRefVars')]['${effectKey}']) + } + + effect(eff${forStartCounter}, trackingKeys) `) ctx.cleanupCode.push(` diff --git a/src/lib/reactivityguard/computedprops.js b/src/lib/reactivityguard/computedprops.js index 8f3248f1..de004f8e 100644 --- a/src/lib/reactivityguard/computedprops.js +++ b/src/lib/reactivityguard/computedprops.js @@ -67,15 +67,21 @@ export default (code) => { const modifications = [] const commentText = ' /* auto-generated reactivity guard */ ' + const computedThisRefVars = [] let match while ((match = componentRegex.exec(code)) !== null) { + const componentMatchStart = match.index const configObject = match[2] // Find computed section with proper brace balancing const computedKeywordMatch = /computed\s*:\s*{/.exec(configObject) if (computedKeywordMatch) { + // Find where config object starts inside the component match + const configObjectStartInComp = match[0].indexOf(match[2]) + // Find start position of the computed block + const computedBlockStart = computedKeywordMatch.index const computedStart = computedKeywordMatch.index + computedKeywordMatch[0].length - 1 // Position of the opening brace // Find the matching closing brace for computed object in config @@ -141,6 +147,12 @@ export default (code) => { let modifiedComputedObj = originalComputedObj let hasChanges = false + // Object to hold this ref variables for current iteration component computed block + const computedPosObj = { + computedStart: componentMatchStart + configObjectStartInComp + computedBlockStart, // adjust to include 'computed: ' + thisRefVars: {}, + } + for (const prop of computedProps) { const thisRefs = extractThisReferences(prop.body) @@ -153,6 +165,10 @@ export default (code) => { continue } + // Collect this ref variables + const thisRefVariablesList = Array.from(thisRefs).map((ref) => ref.replace('this.', '')) + computedPosObj.thisRefVars[prop.name] = thisRefVariablesList + // reactivity code const refCode = Array.from(thisRefs) .map((ref) => `${ref};`) @@ -189,6 +205,9 @@ export default (code) => { } if (hasChanges) { + // Store this ref variables for current iteration component computed block + computedThisRefVars.push(computedPosObj) + // Store the modification of the entire computed object modifications.push({ original: originalComputedObj, @@ -202,6 +221,19 @@ export default (code) => { // Apply all modifications at once, from last to first to preserve positions if (modifications.length > 0) { let modifiedCode = code + + // Insert computedThisRefVars objects in each component code + for (let i = computedThisRefVars.length - 1; i >= 0; i--) { + const obj = computedThisRefVars[i] + modifiedCode = + modifiedCode.slice(0, obj.computedStart) + + '\n' + + 'computedThisRefVars :' + + JSON.stringify(obj.thisRefVars, null, 2) + + ',\n' + + modifiedCode.slice(obj.computedStart) + } + // Sort modifications from last to first to avoid position changes modifications.sort((a, b) => { const posA = modifiedCode.indexOf(a.original) diff --git a/src/lib/symbols.js b/src/lib/symbols.js index 7c4481bd..4bd16ac4 100644 --- a/src/lib/symbols.js +++ b/src/lib/symbols.js @@ -47,6 +47,7 @@ * @property {symbol} isComponent * @property {symbol} effects * @property {symbol} removeGlobalEffects + * @property {symbol} computedThisRefVars */ /** @@ -58,7 +59,6 @@ export default { cleanup: Symbol('cleanup'), currentView: Symbol('currentView'), cursorTagStart: Symbol('cursorTagStart'), - computedKeys: Symbol('computedKeys'), destroy: Symbol('destroy'), rendererEventListeners: Symbol('rendererEventListeners'), getChildren: Symbol('getChildren'), @@ -113,4 +113,9 @@ export default { effects: Symbol.for('effects'), // Symbol 'removeGlobalEffects' utilized within generated code removeGlobalEffects: Symbol.for('removeGlobalEffects'), + // Symbol 'computedThisRefVars' utilized within generated code + computedThisRefVars: Symbol.for('computedThisRefVars'), + + // Symbol 'computedKeys' utilized within generated code + computedKeys: Symbol.for('computedKeys'), }