0

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`
                    })
                ]
            })
        ])
    })
)
13
  • 1
    You need a proxy for the array itself. Changing the array doesn't do anything to the object that references it. Commented Jan 25, 2024 at 20:30
  • 1
    "or changes like array.filter((x, index) => index !== some)": that's not a change. Commented Jan 25, 2024 at 20:35
  • @trincot I was mean array = array.filter(...) Commented Jan 25, 2024 at 21:33
  • That just assigns a new array to an array variable, and will not change the array being referenced by your (proxied) object. Commented Jan 25, 2024 at 21:34
  • @Barmar thanks for your reply. Thats the point actually, that im trying to avoid (potentualy) unnecessary proxyfying properties inside of object, even if property is array. I just dont actually get it why i can track array pushes but not filters/deletes. Ofcourse we can afford it to create a proxy in proxy etc to track everything we need in envs like node, but any changes or additional proxies affects the DOM. So thats why this question was asked. Commented Jan 25, 2024 at 21:39

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.