S
SolidJS•4w ago
Paul

How to create or clone a component and add props to it

I have this snippet in react:
const _children = Children.toArray(children);
const items = _children.map((item: any, index) =>
cloneElement(item, {
unstyled,
__align: align,
__active:
item.props?.active ||
(reverseActive ? active! >= _children.length - index - 1 : active! >= index),
__lineActive:
item.props?.lineActive ||
(reverseActive ? active! >= _children.length - index - 1 : active! - 1 >= index),
})
);
const _children = Children.toArray(children);
const items = _children.map((item: any, index) =>
cloneElement(item, {
unstyled,
__align: align,
__active:
item.props?.active ||
(reverseActive ? active! >= _children.length - index - 1 : active! >= index),
__lineActive:
item.props?.lineActive ||
(reverseActive ? active! >= _children.length - index - 1 : active! - 1 >= index),
})
);
I've searched around this discord a lot and can't seem to find anything that directly answers the question. How can I duplicate the above, i.e clone a component and inject props into it? I've tried to use Dynamic but it just gives me an empty response back. Thanks
16 Replies
zulu
zulu•4w ago
can you create a minimal example in https://playground.solidjs.com/
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
zulu
zulu•4w ago
but remember that solid components do not really exists
Paul
PaulOP•4w ago
Sadly I am unable to. I'm porting over mantine from react to solid and there is a lot of code that stands up even a single component. Yep. I realise that. 😄 All I'm looking for is even a basic poc to follow.
zulu
zulu•4w ago
let say you have this
<Parent>
<Child>1</Child>
</Parent>
<Parent>
<Child>1</Child>
</Parent>
in the Parent when you call props.children, it is already too late to inject any props to the <Child/> This is how it is compiled
return [_$createComponent(Parent, {
get children() {
return _$createComponent(Child, {
children: "1"
});
}
})
return [_$createComponent(Parent, {
get children() {
return _$createComponent(Child, {
children: "1"
});
}
})
Paul
PaulOP•4w ago
I would have thought something like this would work:
const content = () => {
const c = resolved.toArray().filter((item) => !!item);

return c.map((node: any, index: number) => {
// Instead of cloning, use Dynamic to render the component with additional props
const isActive =
node.active ||
(local.reverseActive
? local.active! >= c.length - index - 1
: local.active! >= index);

const isLineActive =
node.lineActive ||
(local.reverseActive
? local.active! >= c.length - index - 1
: local.active! - 1 >= index);

// Create new props to merge with the original component's props
const additionalProps = {
unstyled: local.unstyled,
__align: local.align,
__active: isActive,
__lineActive: isLineActive
};

// Use Dynamic to render the component with merged props
return <Dynamic component={node} props={additionalProps} />;
});
};
const content = () => {
const c = resolved.toArray().filter((item) => !!item);

return c.map((node: any, index: number) => {
// Instead of cloning, use Dynamic to render the component with additional props
const isActive =
node.active ||
(local.reverseActive
? local.active! >= c.length - index - 1
: local.active! >= index);

const isLineActive =
node.lineActive ||
(local.reverseActive
? local.active! >= c.length - index - 1
: local.active! - 1 >= index);

// Create new props to merge with the original component's props
const additionalProps = {
unstyled: local.unstyled,
__align: local.align,
__active: isActive,
__lineActive: isLineActive
};

// Use Dynamic to render the component with merged props
return <Dynamic component={node} props={additionalProps} />;
});
};
zulu
zulu•4w ago
check my last message, tell me if it make sense
Paul
PaulOP•4w ago
I do get it.
zulu
zulu•4w ago
ok, so you understand why you can't really rerun/clone the component by accessing the rendered elements. If you can get to this then the parent can inject its own props to the child
<Parent>
{[(p)=><Child {...p}>1</Child>]}
</Parent>
<Parent>
{[(p)=><Child {...p}>1</Child>]}
</Parent>
Paul
PaulOP•4w ago
I'm not really sure this will work for my codebase. I think I'll look at other solid ui repos and see if there are any answers there.
zulu
zulu•4w ago
what does the code suppose to do?
Paul
PaulOP•4w ago
It's injecting
unstyled, __align, __active, __lineActive
unstyled, __align, __active, __lineActive
into the component props. as in the actual usage of the component is:
<Timeline>
<Timeline.Item>
<Timeline>
<Timeline.Item>
Timeline.Item is the children in this case. And then in Timeline.Item, in it's props. It will find those items and then do "stuff" depending on what props are available.
zulu
zulu•4w ago
I think you might be looking at using Context Providers https://docs.solidjs.com/concepts/context
Paul
PaulOP•4w ago
I've seen that mentioned a few times in this discord. I'm still not sure. With this migration, I've had to move nearly all of the contexts to stores as they simply wouldn't work. It's probably a skill issue atm. Which I'll take a look at once this migration is completed. I do appreciate the suggestions though. 😄
zulu
zulu•4w ago
I am judging by the use case
<Timeline>
<Timeline.Item>
<Timeline>
<Timeline.Item>
there are 2 common ways to communicate between components Parent->Child props (explicit communication) which works if the nested component is declared in the Parent, the parent can explicitly pass any prop it needs to. it does not work when "Injected" such in the case of <Timeline> ( Similar common example is with <Tabs><Tab> and that is when communication over context is used The <Timeline> provides the state to all it's children so it can be used as a way to tell children which item is active for example, or pass any other property
zulu
zulu•4w ago
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
Paul
PaulOP•3w ago
Oh nice, that's pretty cool. Thanks for the poc. I'll take a look at this tomorrow morning as it's 10pm here vs my code and I'll let you know what I come up with. I appreciate the effort. Thanks! I managed to fix my context problem upstream. So in the end I went with using the context to track the number of children and within the sub component then to output what it needed per the index in the children it was.

Did you find this page helpful?