S
SolidJS10mo ago
Andre

Passing "up" signals in Solid

I am trying to understand how can you go by reading values from signals defined in children components in SolidJS. I exemplified my situation in the code bellow (with a solution that I came up with but don’t know if is ideal): I have one component that handles the content being edited (RecordEditor). The submission of the content written by the user is supposed to happens up in the hierarchy, in the AddRecordModal component. That means I need to “access the signals on the children component”.
function AddRecordModal(props: Props) {
const [title, setTitle] = createSignal<string>("");
const [amount, setAmount] = createSignal<number>();

createEffect(() => {
console.log(title(), amount());
});

return (
<div>
<RecordEditor class={styles.content} title={[title, setTitle]} amount={[amount, setAmount]} />
<button onClick={() => console.log(title(), amount())}>Submit record</button>
</div>
);
}

function RecordEditor(props: {
class?: string;
title: [Accessor<string>, Setter<string>];
amount: [Accessor<string | number | undefined>, Setter<number | undefined>];
}) {
const [title, setTitle] = props.title || createSignal<string>();
const [amount, setAmount] = props.amount || createSignal<number>();

return (
<div class={clsx(styles.container, props.class)}>
<input type="text" placeholder="Title" value={title()} onInput={(e) => setTitle(e.currentTarget.value)} />
<input
type="number"
placeholder="Amount"
value={amount()}
onInput={(e) => setAmount(parseFloat(e.currentTarget.value))}
/>
</div>
);
}
function AddRecordModal(props: Props) {
const [title, setTitle] = createSignal<string>("");
const [amount, setAmount] = createSignal<number>();

createEffect(() => {
console.log(title(), amount());
});

return (
<div>
<RecordEditor class={styles.content} title={[title, setTitle]} amount={[amount, setAmount]} />
<button onClick={() => console.log(title(), amount())}>Submit record</button>
</div>
);
}

function RecordEditor(props: {
class?: string;
title: [Accessor<string>, Setter<string>];
amount: [Accessor<string | number | undefined>, Setter<number | undefined>];
}) {
const [title, setTitle] = props.title || createSignal<string>();
const [amount, setAmount] = props.amount || createSignal<number>();

return (
<div class={clsx(styles.container, props.class)}>
<input type="text" placeholder="Title" value={title()} onInput={(e) => setTitle(e.currentTarget.value)} />
<input
type="number"
placeholder="Amount"
value={amount()}
onInput={(e) => setAmount(parseFloat(e.currentTarget.value))}
/>
</div>
);
}
5 Replies
Raqueebuddin Aziz
Either make the signal global, in a context or in the parent component
jer3m01
jer3m0110mo ago
For small numbers of signals your approach is correct, more commonly we set 2 (or 3 with default) props per signal instead of an array. (If you want to use multiple props I'd recommend copying this utility, usage example) Otherwise for many signals a context is easier to manage: https://docs.solidjs.com/concepts/context.
Andre
AndreOP10mo ago
Ok! Thank you so much for the examples, that was what I was needing the most! I just didn't get what you meant by "more commonly we set 2 (or 3 with default) props per signal instead of an array." Since those two components are directly in contact, I think context would be too much in this case so I wanted to find if there a less complex route
jer3m01
jer3m0110mo ago
Instead of title: [Accessor<string>, Setter<string>]; we set 2/3 props:
title: string;
defaultTitle: string;
onTitleChange: Setter<string>;
title: string;
defaultTitle: string;
onTitleChange: Setter<string>;
then used as:
const [title, setTitle] = createControllableSignal({
defaultValue: () => props.defaultTitle ?? "other default",
onChange: props.onTitleChange,
value: () => props.title,
});

title() // string
setTitle("updated title")
const [title, setTitle] = createControllableSignal({
defaultValue: () => props.defaultTitle ?? "other default",
onChange: props.onTitleChange,
value: () => props.title,
});

title() // string
setTitle("updated title")
parent component:
const [title, setTitle] = createSignal<string>("");
<RecordEditor title={title} onTitleChange={setTitle} />
// or
<RecordEditor defaultTitle="default title controlled entirely by subcomponent" />
const [title, setTitle] = createSignal<string>("");
<RecordEditor title={title} onTitleChange={setTitle} />
// or
<RecordEditor defaultTitle="default title controlled entirely by subcomponent" />
Andre
AndreOP10mo ago
Ohh, ok!! That makes sense, thanks for the example!!
Want results from more Discord servers?
Add your server