Context, props and children
createContext and useContext keep their names.
createContext and useContext keep their names. The provider can be written either way, and a context without a
provider and without a default throws, which makes Solid's "guard useMyContext" helper unnecessary.
Context, selector and list: Solid and ShadowJS#
Solid (not executed):
tsx
import { createContext, createSelector, createSignal, For, useContext } from "solid-js";
const Theme = createContext(() => "light");
function Row(props) {
const theme = useContext(Theme);
return <li classList={{ active: props.active, dark: theme() === "dark" }}>{props.label}</li>;
}
function Picker() {
const [theme, setTheme] = createSignal("light");
const [selected, setSelected] = createSignal(1);
const isSelected = createSelector(selected);
return (
<Theme.Provider value={theme}>
<For each={items}>{(item) => <Row active={isSelected(item.id)} label={item.label} />}</For>
</Theme.Provider>
);
}
ShadowJS: useSelector, useStore, and either provider form. Selecting a row updates only the two rows whose state
changed, and a theme change reaches every row through the context accessor.
src/picker.tsxtsx
import { type Accessor, createContext, useContext, useEffect, useSelector, useStore } from "@shadow-js/core";
import { For } from "@shadow-js/web";
const Theme = createContext<Accessor<string>>(() => "light");
/** Every time a row's `active` binding ran, as `id:active`. */
export const log: string[] = [];
const ITEMS = [
{ id: 1, label: "One" },
{ id: 2, label: "Two" },
{ id: 3, label: "Three" },
];
function Row(props: { id: number; label: string; active: boolean; onSelect: (id: number) => void }) {
const theme = useContext(Theme);
useEffect(() => {
log.push(`${props.id}:${props.active}`);
});
return (
<li data-testid={`row-${props.id}`} classList={{ active: props.active, dark: theme() === "dark" }}>
<button type="button" onClick={() => props.onSelect(props.id)}>
{props.label}
</button>
</li>
);
}
export function Picker() {
const [theme, setTheme] = useStore("light");
const [selected, setSelected] = useStore(1);
const isSelected = useSelector(selected);
return (
<Theme value={theme}>
<ul>
<For each={ITEMS}>
{(item) => <Row id={item.id} label={item.label} active={isSelected(item.id)} onSelect={setSelected} />}
</For>
</ul>
<button type="button" onClick={() => setTheme("dark")}>
Dark
</button>
</Theme>
);
}