I am trying to track some array changes inside of proxyfied object. For example:
object = {
count: 0,
input: ``,
tasks: [ ]
}
and I need to track changes of object.tasks.
The problem is that proxy catches all changes (set, get etc.) related to object, and even array (object.tasks) sets (means event 'set' fires and traps array changes, but not removes (delete) like delete object.tasks[someIndex], or changes like array.filter((x, index) => index !== some) and so on.
So my question is: what's the proper way to trap this changes?
upd:
const createElement = (any) => {
const { tagName = undefined, className = '', id = undefined, state = { }, render = undefined, ...some } = any
const element = tagName ? document.createElement(tagName) : document.createDocumentFragment()
if(tagName){
if(className) element.className = className
if(id) element.id = id
}
if(render){
if(state){
element.state = new Proxy(state, {
deleteProperty(entry, v){
console.log(entry, v)
delete(entry[v])
return true
},
set(entry, k, v){
if(entry[k] !== v){
console.log(entry, v)
entry[k] = v
const children = render({ state: entry })
element.childNodes.forEach((child, i) => {
if(typeof(children[i]) === 'string' || typeof(children[i]) === 'number') children[i] = document.createTextNode(children[i])
!children[i].isEqualNode(child) && element.replaceChild(children[i], child) && console.log('Element updated: ', children[i])
})
} else {
console.log(k, v)
}
return true
}
})
}
const children = render({ state: element.state })
if(typeof(children) === 'object' && children instanceof(Array)) element.replaceChildren(...children)
else element.replaceChildren(children)
}
if(some){
Object.assign(element, some)
}
return element
}
document.querySelector('#root').replaceChildren(
createElement({ tagName: 'div', className: 'class-test',
render: () => ([
`buttons test (dec/inc)`,
createElement({ tagName: 'div', state: { count: 0 },
render: ({ state }) => [
createElement({ tagName: 'button', className: 'btn-decrease',
onclick: () => state.count--,
render: () => `-`
}),
`Clicked ${ state.count } times...`,
createElement({ tagName: 'button', className: 'btn-increase',
onclick: () => state.count++,
render: () => `+`
})
]
}),
`inputs test (tasks, click on task to remove)`,
createElement({ tagName: 'form', state: { input: ``, tasks: [ ] },
onsubmit: (e) => {
e.preventDefault()
e.target.reset()
},
render: ({ state }) => [
createElement({ tagName: `ul`,
render: () => state.tasks.map((task, i) => createElement({
tagName: 'li',
onclick: () => delete state.tasks[i],
render: () => task
}))
}),
createElement({ tagName: 'input', placeholder: `Text some task..`,
oninput: ({ target }) => state.input = target.value
}),
createElement({ tagName: 'button', type: 'submit',
onclick: () => state.input ? state.tasks.push(state.input) && (state.input = ``) : null,
render: () => `Set task`
})
]
})
])
})
)
arrayvariable, and will not change the array being referenced by your (proxied) object.