order of reactivity

Hi, i have this component
export default function Orders() {

const [displayMode, setDisplayMode] = createSignal("customer")
const [orders] = createResource(displayMode, getOrders)


const switchDisplayMode = () => {
setDisplayMode(displayMode() == "customer" ? "product" : "customer")
console.log(displayMode(), orders.loading)
}


return <div class="container mx-auto">
<div class="h-30 py-4 [&>*]:mx-2">
<Button variant="contained" color="success" href="/orders/new">New order</Button>
<Button variant="contained" color="primary" onClick={switchDisplayMode}>{displayMode() == "customer" ? "Display by products" : "Display by customers"}</Button>
</div>

<Show when={displayMode() == "customer" && !orders.loading}>
<ByCustomerTable orders={orders()} />
</Show>

<Show when={displayMode() == "product" && !orders.loading}>
<ByProductTable orders={orders()} />
</Show>

</div>
}
export default function Orders() {

const [displayMode, setDisplayMode] = createSignal("customer")
const [orders] = createResource(displayMode, getOrders)


const switchDisplayMode = () => {
setDisplayMode(displayMode() == "customer" ? "product" : "customer")
console.log(displayMode(), orders.loading)
}


return <div class="container mx-auto">
<div class="h-30 py-4 [&>*]:mx-2">
<Button variant="contained" color="success" href="/orders/new">New order</Button>
<Button variant="contained" color="primary" onClick={switchDisplayMode}>{displayMode() == "customer" ? "Display by products" : "Display by customers"}</Button>
</div>

<Show when={displayMode() == "customer" && !orders.loading}>
<ByCustomerTable orders={orders()} />
</Show>

<Show when={displayMode() == "product" && !orders.loading}>
<ByProductTable orders={orders()} />
</Show>

</div>
}
when i click the button i want to change display mode, based on display mode i want to fetch new data and then display it in the show tag the issue is, when the displaymode changes first it triggers the shows and that errors out because each show is anticipating different data structure which is not fetched yet
4 Replies
Maciek50322
Maciek503228mo ago
Interesting, this is probably a bug, I managed to reproduce it here https://playground.solidjs.com/anonymous/d73a3b0c-7e04-4301-b76e-a02e13952d2b First time button is clicked, everything is alright, but second time the error throws
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
Maciek50322
Maciek503228mo ago
As a workaround if you wrap <Show>'s children as function, you get desired behavior without errors, like
<Show when={displayMode() == "customer" && !orders.loading}>
{() => <ByCustomerTable orders={orders()} />}
</Show>
<Show when={displayMode() == "customer" && !orders.loading}>
{() => <ByCustomerTable orders={orders()} />}
</Show>
Even more interestingly, if you passed argument to this function (that is result accessor of when), you get same error, so for now don't do
{(x) => <ByCustomerTable orders={orders()} />}
{(x) => <ByCustomerTable orders={orders()} />}
Also <Switch> with <Match> aren't affected by this error. Note: this happens, because <Show> evaluates immediately it's children when children are: not a function, function with any arguments. Also because .loading state gets updated little later than displayMode, and so the when quickly switches between true and false (because displayMode = true && .loading = false, then .loading gets updated), when changing displayMode, and then after request fetched, back to true. If we pass children so that <Show> immediately evaluates it, in this quick switching to true and false, it creates the component, that doesn't have valid data - this generates error. If we pass children as function without argument, then when when = true it doesn't evaluate it, just passes it to render. But when changes quickly to false, and before renderer handled passed function, it gets replaced by fallback (nothing in this case), and so shows nothing, as it should, until valid data is fetched (.loading = false).
Chronove
Chronove8mo ago
I'd say a better workaround would be to use the proper components for it. Solid does provide a switch/match component, making it:
<Switch>
<Match when={displayMode() == "customer" && !orders.loading}>
<ByCustomerTable orders={orders()} />
</Match>
<Match when={displayMode() == "product" && !orders.loading}>
<ByProductTable orders={orders()} />
</Match>
</Switch>
<Switch>
<Match when={displayMode() == "customer" && !orders.loading}>
<ByCustomerTable orders={orders()} />
</Match>
<Match when={displayMode() == "product" && !orders.loading}>
<ByProductTable orders={orders()} />
</Match>
</Switch>
Maciek50322
Maciek503228mo ago
Sure, but this is unexpected behavior and something probably needs to change
Want results from more Discord servers?
Add your server