Replies: 4 comments 9 replies
-
Why not use props? Changing a prop from the parent will trigger reactive effects inside the child component. |
Beta Was this translation helpful? Give feedback.
-
If you need to update a child state from its parent, elevating the state to the parent component is the easiest and most performant option. There are other methods too but since you specifically asked a solution that uses props, best option is, as always, using a callback. import { Component, Setter, createSignal } from 'solid-js';
import { render } from 'solid-js/web';
const Child: Component<{ updateHandler: (setter: Setter<number>) => void }> = (
props,
) => {
const [count, setCount] = createSignal(50);
props.updateHandler(setCount);
return <div>Count: {count()}</div>;
};
export const App = () => {
let handler: undefined | Setter<number>;
const reset = () => {
handler && handler(0);
};
const updateHandler = (next: Setter<number>) => {
handler = next;
}
return (
<div>
<button onclick={reset}>Inc</button>
<Child updateHandler={updateHandler} />
</div>
);
};
render(App, document.body); A simple assignment will not work because we would be updating the props property not the actual variable: import { Component, Setter, createSignal } from 'solid-js';
import { render } from 'solid-js/web';
const Child: Component<{ handler: undefined | Setter<number> }> = (
props,
) => {
const [count, setCount] = createSignal(50);
props.handler = setCount;
return <div>Count: {count()}</div>;
};
export const App = () => {
let handler: undefined | Setter<number>;
const reset = () => {
handler && handler(0);
};
return (
<div>
<button onclick={reset}>Inc</button>
<Child handler={handler} />
</div>
);
};
render(App, document.body); If you keep the state for updating the UI, it is best to create a ref function inside the parent component and pass it to the child. You can use either variable form or function form for the ref, I used function form for clarity. import { Component, createSignal } from 'solid-js';
import { render } from 'solid-js/web';
const Child: Component<{ divRef: (el: HTMLDivElement) => void }> = (props) => {
const [count, setCount] = createSignal(50);
return <div ref={props.divRef}>Count: {count()}</div>;
};
export const App = () => {
let divEl: HTMLDivElement | undefined;
function divRef(el: HTMLDivElement) {
console.log(el);
divEl = el;
}
const handleClick = () => {
divEl!.style.setProperty('color', 'red');
};
return (
<div>
<button onclick={handleClick}>Change Color</button>
<Child divRef={divRef} />
</div>
);
};
render(App, document.body); |
Beta Was this translation helpful? Give feedback.
-
As others have already mentioned, For example, let's say you create a headless video player component that only renders the video, but it's the job of the host / parent component to implement the UI. The parent component will have to implement buttons which, when clicked, will have to tell the player component what to do. Here's working sample code that mimics the above by implementing a https://playground.solidjs.com/anonymous/00c1534f-cb43-4321-9ee4-dffbdef75fed An outline of what's happening would be: Child componentconst Player = (props) => {
const isPlaying = () => {/* implementation */ }
const play = () => {/* implementation */ }
const pause = () => {/* implementation */ }
const rewind = () => {/* implementation */ }
onMount(() => {
// 👇 This is how you expose your component's API
props.ref?.({ play, pause, rewind, isPlaying });
onCleanup(() => {/* implementation */ })
});
return <>render something</>
}; Parent componentexport const App = () => {
let player;
const togglePlayback = () => {
if (player?.isPlaying()) {
player?.pause()
} else {
player?.play()
}
};
const rewind = () => {
player?.rewind()
}
return (
<div>
<Player ref={player} />
<hr />
<button type="button" onClick={rewind}>↩️</button>
<button type="button" onClick={togglePlayback}>⏯️</button>
</div>
);
}; One small issue with One way to stop Typescript from complaining about this, would be to use an identity function that simply returns the same component unmodified, but alters the type signature of the component. import { type Component } from 'solid-js';
export function forwardRef<R, P>(
component: Component<P & { ref?: (val: R) => void }>,
): Component<P & { ref?: R }> {
return component as any;
} and would be used like this type ChildProps = {/* props */}
type ChildRef = {/* exposed API */}
const Child = forwardRef<ChildRef, ChildProps>(props => {
return <>implementation</>
})
const Parent = () => {
let child: undefined | ChildRef
return <Child ref={child} />
} This will ensure proper typings on both the child's (You can see the same Hope this helps (both the OP and others that might stumble onto this discussion)! 👍 |
Beta Was this translation helpful? Give feedback.
-
I agree with @JaielZeus on this topic. SolidJS is very elegant until you arrive at this topic of Component communication. |
Beta Was this translation helpful? Give feedback.
-
I am really missing an easy way of communicating things between parent and children components. I can use props in SolidJS to give a callback to a child component so the children can invoke things in the parent easily. Thats fine and dandy but what about the other way around? I would like to invoke a fucntion or signal inside of the child somehow. I could imagine giving a signal down to the child and the child can create an effect and react to the signal changed like that.
I think though there could exist an easier more elegant way in solid to accomplish that even if it is all just syntactic sugar in the end over the mechanism we can use right now to accomplish this as I described. What do you think?
Beta Was this translation helpful? Give feedback.
All reactions