Open timkelty opened 4 years ago
FWIW, I tried to make a custom factory for doing this, but by the time the factory's inject
method is called, target
is already the modified data-habitat
element, and thus the children have been removed.
Here is my custom factory that does this…it is a bit hacky because it relies on the replaceDisabled
option being true
.
class MyCustomFactory {
inject(module, props, target) {
if (target) {
const childProps = this.getChildProps(target);
ReactDOM.render(
React.createElement(module, Object.assign({}, childProps, props || {})),
target,
);
} else {
Logger.warn('RHW07', 'Target element is null or undefined.');
}
}
dispose(target) {
if (target) {
ReactDOM.unmountComponentAtNode(target);
}
}
getChildProps(target, remove = true) {
const {previousElementSibling} = target;
const children = previousElementSibling && previousElementSibling.querySelectorAll('[data-prop]') || [];
return [...children].reduce((obj, el) => {
if (remove) {
el.remove();
}
return Object.assign(obj, {
[el.dataset.prop]: el,
});
}, {});
}
}
Example Usage…
<div data-component="MyComponent" data-props='{"foo": "bar"}' data-habitat-no-replace="true">
<div data-prop="someContent">
<p>Some content…</p>
</div>
</div>
<div dangerouslySetInnerHTML={{__html: this.props.someContent.innerHTML}} />
Hey @timkelty, I just found a built-in way to do this, using the proxy
prop that is passed to all react-habitat components:
<div dangerouslySetInnerHTML={{__html: this.props.proxy.innerHTML}} />
That wouldn't do any of the child props stuff, but you could do that with something like htmr (which is what I am using) to convert the HTML string to React components.
Then you wouldn't need the data-prop
syntax:
import React from 'react';
import convert from 'htmr';
const MyComponent = ({foo, proxy}) => (
<div>
<p>{foo}</p>
{convert(proxy.innerHTML)}
</div>
);
<div data-component="MyComponent" data-props='{"foo": "bar"}'>
<div className="my-class">
<p>Some content…</p>
</div>
</div>
Renders something like this:
<div data-habitat="C1">
<div>
<p>bar</p>
<div class="my-class">
<p>Some content…</p>
</div>
</div>
</div>
@iainsimmons oh nice!
Every React Habitat instance is passed in a prop named proxy, this is a reference the original dom element.
Didn't realize that!
I thought it would be neat if we were able to register children of the component root:
This could also be used as progressive enhancement, or a way inject SEO data.