Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace handler hook with element_id based approach #11

Merged
merged 2 commits into from
Jan 11, 2025

Conversation

eliknebel
Copy link
Collaborator

@eliknebel eliknebel commented Jan 11, 2025

Removes the handler hook API and replaces it with a more transparent and simpler (at least, from the developer API perspective) element_id-based tracking system. The intent here is to keep the optimization where event ids remain stable across updates even though event handler callback functions may be recreated and re-bound on every render cycle, preventing unnecessary id changes in patches for event handlers.

This work achieves that by adding a stable element_id to the ReconciledElement record and utilizing the existing reconciler diffing logic to determine if an element is the same element as the previous element or if it is a new element that needs a new element_id.

With this new approach, it is no longer necessary for a developer to use hooks to define event handlers and event handling should be much simpler. For example, previously a component would need to be written as such:

fn button_component(ctx: Context, _props) {
  use ctx, count, set_count <- state(ctx, 0)

  // Define event handlers
  use ctx, increment <- handler(ctx, fn(_) { set_count(count + 1) })
  use ctx, reset <- handler(ctx, fn(_) { set_count(0) })

  let current_count = int.to_string(count)

  component.render(
    ctx,
    fragment([
      text("current count is: " <> current_count),
      button([id("increment"), events.on_click(increment)], [
        text("increment"),
      ]),
      button([id("reset"), events.on_click(reset)], [text("reset")]),
    ]),
  )
}

Now with these changes, the component handlers can simply be written as normal functions:

fn button_component(ctx: Context, _props) {
  use ctx, count, set_count <- state(ctx, 0)

  // Define event handlers
  let increment = fn(_) { set_count(count + 1) }
  let reset = fn(_) { set_count(0) }

  let current_count = int.to_string(count)

  component.render(
    ctx,
    fragment([
      text("current count is: " <> current_count),
      button([id("increment"), events.on_click(increment)], [text("increment")]),
      button([id("reset"), events.on_click(reset)], [text("reset")]),
    ]),
  )
}

Or with the handler callback inlined with the markup for simple cases:

fn button_component(ctx: Context, _props) {
  use ctx, count, set_count <- state(ctx, 0)

  let current_count = int.to_string(count)

  component.render(
    ctx,
    fragment([
      text("current count is: " <> current_count),
      button(
        [id("increment"), events.on_click(fn(_) { set_count(count + 1) })],
        [text("increment")],
      ),
      button([id("reset"), events.on_click(fn(_) { set_count(0) })], [
        text("reset"),
      ]),
    ]),
  )
}

@eliknebel eliknebel changed the title Replace handler hook with simpler element id based approach Replace handler hook with element id based approach Jan 11, 2025
@eliknebel eliknebel changed the title Replace handler hook with element id based approach Replace handler hook with element_id based approach Jan 11, 2025
@eliknebel eliknebel merged commit f67826e into master Jan 11, 2025
2 checks passed
@eliknebel eliknebel deleted the events-refactor branch January 11, 2025 19:04
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.

1 participant