Skip to content

fix: useProperty init sets default even when preventDefault is called#157

Merged
megheaiulian merged 3 commits into
mainfrom
fix/use-property-init-preventDefault
Jul 2, 2026
Merged

fix: useProperty init sets default even when preventDefault is called#157
megheaiulian merged 3 commits into
mainfrom
fix/use-property-init-preventDefault

Conversation

@megheaiulian

Copy link
Copy Markdown
Contributor

Problem

When a parent component uses lift() to listen to a child's property change event without passing the property value to the child (no .prop=${value} binding), useProperty's initialization is blocked by preventDefault(), leaving the host property undefined.

This causes TypeError: Cannot read properties of undefined (reading 'length') crashes in components like cosmoz-omnitable's renderFooter when selectedItems is never initialized.

Root cause

useProperty's constructor calls this.updater(initialValue) to set the default. updater dispatches a notification event, and if a lift listener calls ev.preventDefault(), the host property is never set:

updater(valueOrUpdater) {
    const ev = this.notify(value, updater);
    if (ev.defaultPrevented) return;  // ← host property never set on init!
    // ...
    this.state.host[this.property] = value;
}

This is correct for subsequent updates (parent takes over via its own state), but wrong for initialization — the host should always get its default value.

Fix

Add an isInit flag to updater() that bypasses the preventDefault veto during initialization:

updater(valueOrUpdater, isInit = false) {
    const ev = this.notify(value, updater);
    if (!isInit && ev.defaultPrevented) return;  // only veto non-init updates
    // ...
}

Constructor passes true:

this.updater(initialValue, true);

This ensures:

  • The host always gets its default value on init
  • The notification event still fires (so lift syncs parent state)
  • Subsequent updates retain full preventDefault / lift two-way binding semantics

Test

Added a test reproducing the exact scenario: parent uses lift without passing the property, verifying the child's host gets the default [].

When a parent uses lift() to listen to property changes without
passing the property value to the child, useProperty's initialization
event gets preventDefault'd, leaving the host property undefined.

Add isInit flag to updater() so initialization bypasses the
preventDefault veto while subsequent updates retain the full
lift/preventDefault two-way binding semantics.
@changeset-bot

changeset-bot Bot commented Jul 1, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 9ee4a75

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@pionjs/pion Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@netlify

netlify Bot commented Jul 1, 2026

Copy link
Copy Markdown

Deploy Preview for pionjs ready!

Name Link
🔨 Latest commit 9ee4a75
🔍 Latest deploy log https://app.netlify.com/projects/pionjs/deploys/6a45fc48d747db0008741b3b
😎 Deploy Preview https://deploy-preview-157--pionjs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Comment thread test/use-property.test.ts Outdated
Co-authored-by: Cristian Necula <VirusZ@gmail.com>
@megheaiulian

Copy link
Copy Markdown
Contributor Author

And I gotta add a changeset too.

@megheaiulian megheaiulian merged commit 7560f99 into main Jul 2, 2026
9 checks passed
@megheaiulian megheaiulian deleted the fix/use-property-init-preventDefault branch July 2, 2026 06:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants