Skip to content

Conversation

@volkanceylan
Copy link
Contributor

Summary

This pull request introduces two new hooks, jsxDomAttributeHook and jsxDomChildrenHook, to extend the functionality of jsx-dom. These hooks enable developers to integrate reactive libraries like Preact Signals for dynamic DOM updates.

Features

  1. jsxDomAttributeHook: Allows interception of attribute assignment. For example, with Preact Signals, this hook can be added to the Signal prototype to automatically update attribute values when the signal changes.
  2. jsxDomChildrenHook: Enables dynamic replacement of child elements using custom logic, such as placeholder comments.

Use Cases

  • Reactive Attributes: Automatically update DOM attributes when the underlying state changes.
  • Dynamic Children: Replace child elements dynamically based on application logic.
  • Other use cases: Other than signals, can be used to implement logic similar to integrated hooks like useClassList without having to modify jsx-dom.

Compatibility

  • Fully backward-compatible. The hooks are opt-in and do not interfere with existing functionality.

Tests

  • Added comprehensive tests to validate the behavior of the hooks in various scenarios, including edge cases.

Example Usage

import { Signal } from "@preact/signals-core";

Signal.prototype.jsxDomAttributeHook = function (node, attr) {
  // Custom logic for reactive attribute updates
};

Signal.prototype.jsxDomChildrenHook = function (parentNode) {
  // Custom logic for dynamic child replacement
};

I already did a quick implementation for signals-core and tested it successfully.

Next Steps and Things to Consider

  • The hooks adds some overhead, but based on my quick benchmarks, it is around 5 percent.
  • Attributes accept certain types, like string, bool etc. I could add all attributes option to accept a value with the jsxDomAttributeHook, e.g.:
type TOrHookT = T | { jsxDomAttributeHook(): T }
interface SomeElementAttributes {
   someattr: TOrHookT<string | bool>
}

But I did not want to complicate the pull request and for now it is possible to cast to any or use some other tricks.

  • For reactive update of attributes, the hooks would have to duplicate some logic in the attribute function, like "class", "className" handling, dataset / style handling etc. Some of this logic is exported but some of them not, or are not separate functions. Could consider moving the hook to attr / attrNS to make it easier for the hooks to handle updates, but there are several other special handled attributes / props etc. so would also need to modify more places in the code.
  • Currently, the hooks are placed in the passed attribute value / child node. Another option could be to have an exported hooks object like:
export const jsxDomHooks = {
   attribute: function(...),
   children: function(...)
}

And call these for any type of value, but not sure if it would be better, though it would let external libs to intercept any value not just signals etc.

…ribute and child updates

- Introduced `jsxDomAttributeHook` to intercept attribute assignment and enable reactive updates.
- Added `jsxDomChildrenHook` to allow dynamic replacement of child elements using custom logic.
- These hooks are designed to integrate seamlessly with reactive libraries like Preact Signals.
- Ensured backward compatibility by making the hooks opt-in.
- Added tests to validate the functionality of the hooks in various scenarios.

This feature enhances the flexibility of `jsx-dom` by enabling developers to implement reactive DOM updates with minimal effort.
@alex-kinokon
Copy link
Owner

Is there a reason you want to use jsx-dom instead of Preact for reactivity? Seems like you would benefit more from the latter library.

@volkanceylan
Copy link
Contributor Author

I'm already using preact in some samples in our Serenity framework. But the core of the framework and its base Widget class does not work well with vdom approaches due to historic reasons like it was once upon a time based on jQuery UI widgets. I'm also already using preact/signals-core with jsx-dom where I need some reactivity but it adds some manual work. Preact's signals library already has integration with preact and react via hooks. This would allow adding another integration for jsx-dom.

Anyway, after sending this pull req, I have other things to consider. For example, instead of jsxDomAttributeHook etc. would it be better to use symbols like attributeHookSymbol exported from jsx-dom so that these hooks don't show up on Signal objects. Adding some global hook point, or directly supporting signals by adding a isSignalLike function are also other options (in that case jsx-dom should also handle the update). Also, for the implementation, I had to duplicate most of the logic inside attr function so maybe adding a isUpdate argument to that function and exporting it / or providing it via an argument to the attribute hook may also make sense.

I opened this pull req to see if you would be interested in such a feature and discuss. If you think it is out of scope, it is ok. I can already monkey patch jsx-dom or fork it to implement one of this ideas.

@volkanceylan
Copy link
Contributor Author

We decided to go with a version that supports preact signals-core directly. Thank you, closing this.

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