S
SolidJSβ€’5mo ago
binajmen

Is there a way to access children props?

Ih this code:
import { render, Dynamic } from "solid-js/web";
import { children, type ParentProps, For, createEffect } from "solid-js";

function App() {
return (
<Editor>
<Line>First line</Line>
<Line onClick={() => console.log("hey!")}>Second line</Line>
</Editor>
);
}

function Editor(props: ParentProps) {
const lines = children(() => props.children);

return (
<ol>
<For each={lines.toArray()}>
{(child, index) => <Dynamic component={Line} number={index() + 1} />}
</For>
</ol>
);
}

function Line(props: ParentProps<{ number?: number; onClick?: () => void }>) {
return (
<div onClick={() => props.onClick}>
{props.number} - {props.children}
</div>
);
}

render(() => <App />, document.getElementById("app")!);
import { render, Dynamic } from "solid-js/web";
import { children, type ParentProps, For, createEffect } from "solid-js";

function App() {
return (
<Editor>
<Line>First line</Line>
<Line onClick={() => console.log("hey!")}>Second line</Line>
</Editor>
);
}

function Editor(props: ParentProps) {
const lines = children(() => props.children);

return (
<ol>
<For each={lines.toArray()}>
{(child, index) => <Dynamic component={Line} number={index() + 1} />}
</For>
</ol>
);
}

function Line(props: ParentProps<{ number?: number; onClick?: () => void }>) {
return (
<div onClick={() => props.onClick}>
{props.number} - {props.children}
</div>
);
}

render(() => <App />, document.getElementById("app")!);
I was hoping to be able to pass the children props to the dynamic component. Is there a way to do this?
31 Replies
binajmen
binajmenOPβ€’5mo ago
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
binajmen
binajmenOPβ€’5mo ago
the idea would be to pass the children props here:
{(child, index) => <Dynamic component={Line} number={index() + 1} />}
{(child, index) => <Dynamic component={Line} number={index() + 1} />}
bigmistqke
bigmistqkeβ€’5mo ago
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
binajmen
binajmenOPβ€’5mo ago
🀯 this is insanely complex. will have to digest that. thank you though ;D ok its readable i wonder how clean this is
bigmistqke
bigmistqkeβ€’5mo ago
ye it's a bit sneaky πŸ™‚
binajmen
binajmenOPβ€’5mo ago
^^
bigmistqke
bigmistqkeβ€’5mo ago
it would be more readable with a ref but then it would be undefined when getting it from the WeakMap
binajmen
binajmenOPβ€’5mo ago
I believe the original need is sneaky as well and could be solved in another manner but TIL
bigmistqke
bigmistqkeβ€’5mo ago
u could also return non-dom elements
binajmen
binajmenOPβ€’5mo ago
exactly
bigmistqke
bigmistqkeβ€’5mo ago
that is how <Route/> works in solid-router
binajmen
binajmenOPβ€’5mo ago
the other way around. much cleaner
bigmistqke
bigmistqkeβ€’5mo ago
but the WeakMap is maybe less hacky at the end of the day what do you mean?
binajmen
binajmenOPβ€’5mo ago
it was a good and valid use case for WeakMap ;D i meant having the props defined and just loop on it. probably dozen of solutions to avoid such cryptic solution. however I applaud the way of thinking outside the box πŸ‘ ty πŸ™‚
bigmistqke
bigmistqkeβ€’5mo ago
you are very welcome! i love these kind of sneaky stuff 😁
binajmen
binajmenOPβ€’5mo ago
XD
bigmistqke
bigmistqkeβ€’5mo ago
solid's jsx is so flexible u can really do whatever
binajmen
binajmenOPβ€’5mo ago
yeah i forgot that it is. the fact you can do vanilla js so easily inside of solid is awesome
bigmistqke
bigmistqkeβ€’5mo ago
exactly, a div is a div πŸ™‚
Danny
Dannyβ€’5mo ago
What about storing the props in a symbol property in the element itself? That way you have direct access to it.
binajmen
binajmenOPβ€’5mo ago
can you extend on that? im not sure what your suggestion is πŸ˜’
Danny
Dannyβ€’5mo ago
I think I should ask first if you are familiar with the Symbol primitive value of JS to make sure we are on the same page.
bigmistqke
bigmistqkeβ€’5mo ago
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
Dakotys
Dakotysβ€’5mo ago
Or you can omit Dynamic component altogether and make Line return accessor instead ( we are not unnecessarily recreating Lines html node and then ignoring it and sneaking original props around but directly passing new constructor): https://playground.solidjs.com/anonymous/40015254-f106-4a3f-ab38-e62cd7018fa9
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
Dakotys
Dakotysβ€’5mo ago
Or forward everything to Editor and let him do the heavy lifting: https://playground.solidjs.com/anonymous/c4d4a3e4-48ec-46a1-ad5f-18d9b415f707
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
Madaxen86
Madaxen86β€’5mo ago
If it is just about numbering, you can do this with css and save all the trouble: https://blog.logrocket.com/styling-numbered-lists-with-css-counters/ Otherwise I usually create a context on the parent (the Editor in this case) and provide a map to which each child can add itself (its ref) onMount and remove itself onCleanup. And the component can then determine its index by himself by finding itself in the map. This is how component libraries like kobalte.dev do it as well.
Supun Kavinda
LogRocket Blog
Styling numbered lists with CSS counters - LogRocket Blog
With CSS counters, you can customize the appearance of the numbers in an ordered list without adding more elements to the DOM.
bigmistqke
bigmistqkeβ€’5mo ago
Otherwise I usually create a context on the parent (the Editor in this case) and provide a map to which each child can add itself (its ref) onMount and remove itself onCleanup.
Doesn't this fail when there is conditional rendering and you count on order of the children? Or swapping order of elements with <For/>
Madaxen86
Madaxen86β€’5mo ago
Thatβ€˜s right. If you render components conditionally: yes Thatβ€˜s why the css solution is so great.😁 But you can sort the items before setting:
function Editor(props: ParentProps) {
return (
<ol>
{props.children}
</ol>
);
}

function sortByDocumentPosition(a: Node, b: Node) {
const position = a.compareDocumentPosition(b);

if (
position & Node.DOCUMENT_POSITION_FOLLOWING ||
position & Node.DOCUMENT_POSITION_CONTAINED_BY
) {
return -1;
}

if (
position & Node.DOCUMENT_POSITION_PRECEDING ||
position & Node.DOCUMENT_POSITION_CONTAINS
) {
return 1;
}

return 0;
}

const [items,setItems] = createSignal<Node[]>([])
const addItem = (item:Node|undefined) => {item && setItems(prev =>[...prev,item].sort(sortByDocumentPosition))}
const removeItem = (item:Node|undefined) => {
const removed = items().filter(o=> o!==item)
setItems(removed)
}
function Line(props: ParentProps<{ number?: number; onClick?: () => void }>) {
const [ref,setRef] = createSignal<Node|undefined>()
onMount(()=>addItem(ref()))
onCleanup(()=>removeItem(ref()))


return (
<div onClick={() => props.onClick?.()} ref={setRef}>
{items()?.indexOf(ref()!)+1} - {props.children}
</div>
);
}
function Editor(props: ParentProps) {
return (
<ol>
{props.children}
</ol>
);
}

function sortByDocumentPosition(a: Node, b: Node) {
const position = a.compareDocumentPosition(b);

if (
position & Node.DOCUMENT_POSITION_FOLLOWING ||
position & Node.DOCUMENT_POSITION_CONTAINED_BY
) {
return -1;
}

if (
position & Node.DOCUMENT_POSITION_PRECEDING ||
position & Node.DOCUMENT_POSITION_CONTAINS
) {
return 1;
}

return 0;
}

const [items,setItems] = createSignal<Node[]>([])
const addItem = (item:Node|undefined) => {item && setItems(prev =>[...prev,item].sort(sortByDocumentPosition))}
const removeItem = (item:Node|undefined) => {
const removed = items().filter(o=> o!==item)
setItems(removed)
}
function Line(props: ParentProps<{ number?: number; onClick?: () => void }>) {
const [ref,setRef] = createSignal<Node|undefined>()
onMount(()=>addItem(ref()))
onCleanup(()=>removeItem(ref()))


return (
<div onClick={() => props.onClick?.()} ref={setRef}>
{items()?.indexOf(ref()!)+1} - {props.children}
</div>
);
}
Madaxen86
Madaxen86β€’5mo ago
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
bigmistqke
bigmistqkeβ€’5mo ago
TIL about compareDocumentPosition and Node.DOCUMENT_POSITION_PRECEDING and the like. Node.DOCUMENT_POSITION_PRECEDING is like a global of the current comparison? strange api!
binajmen
binajmenOPβ€’5mo ago
lots of valid suggestion, brains are cooking here ;D
Want results from more Discord servers?
Add your server