Parent doesn't update view when state changes.

Problem: when the child component modifies the state of Auth, the rendering doesn't update. Auth component:
function Auth() {
const [viewLogin, setViewLogin] = createSignal(true);

createEffect(() => console.log(viewLogin())); // prints false after button in Login is clicked.

return (
viewLogin() ?
<Login viewState={setViewLogin} /> :
<Register viewState={setViewLogin} />
);
}
function Auth() {
const [viewLogin, setViewLogin] = createSignal(true);

createEffect(() => console.log(viewLogin())); // prints false after button in Login is clicked.

return (
viewLogin() ?
<Login viewState={setViewLogin} /> :
<Register viewState={setViewLogin} />
);
}
Login component:
function Login(
{ viewState }:
{ viewState: (b: boolean) => void })
{

const toggleState = () => {
viewState(false);
}

return (
<button onClick={() => toggleState()}>Create one now.</button>
)
}

export default Login;
function Login(
{ viewState }:
{ viewState: (b: boolean) => void })
{

const toggleState = () => {
viewState(false);
}

return (
<button onClick={() => toggleState()}>Create one now.</button>
)
}

export default Login;
15 Replies
Alex Lohr
Alex Lohr2y ago
Early return issue. Either wrap the ternary in {} or even better use <Show> Longer explanation: solid.js runs components only once. You have effects, memos and JSX expressions (basically everything between {}) to opt in to reactive handling. Everything else will stay unchanged. So using return c ? 'a' : 'b' will never update, regardless of state changes. This is by design; it allows solid to achieve top performance by not doing anything unnecessary.
Mr Void
Mr VoidOP2y ago
I see. I currently have this and now the state is true even when the button is clicked
return (
<Show
when={viewLogin()}
fallback={<Register viewState={setViewLogin} />}
>
<Login viewState={setViewLogin} />
</Show>
);
return (
<Show
when={viewLogin()}
fallback={<Register viewState={setViewLogin} />}
>
<Login viewState={setViewLogin} />
</Show>
);
Alex Lohr
Alex Lohr2y ago
Oh, I overlooked that. You return the function in the event handler instead of calling it. <button onClick={toggleState} Instead of () => toggleState.
Mr Void
Mr VoidOP2y ago
did not change the behaviour, the state remains as true 🤔
Alex Lohr
Alex Lohr2y ago
Ah, missed the () behind the event. Stupid mobile formatting. Can you show me your current code?
Mr Void
Mr VoidOP2y ago
function Login(
{ viewState }:
{ viewState: (b: boolean) => void })
{

const toggleState = () => {
viewState(false);
}

return (
<button onClick={toggleState}>Create one now.</button>
)
}

export default Login;
function Login(
{ viewState }:
{ viewState: (b: boolean) => void })
{

const toggleState = () => {
viewState(false);
}

return (
<button onClick={toggleState}>Create one now.</button>
)
}

export default Login;
Alex Lohr
Alex Lohr2y ago
Specifically that of the login component. Thanks
Mr Void
Mr VoidOP2y ago
and auth:
function Auth() {
const [viewLogin, setViewLogin] = createSignal(true);

createEffect(() => console.log(viewLogin()));

return (
<Show
when={viewLogin()}
fallback={<Register viewState={setViewLogin} />}
>
<Login viewState={setViewLogin} />
</Show>
);
}
function Auth() {
const [viewLogin, setViewLogin] = createSignal(true);

createEffect(() => console.log(viewLogin()));

return (
<Show
when={viewLogin()}
fallback={<Register viewState={setViewLogin} />}
>
<Login viewState={setViewLogin} />
</Show>
);
}
Alex Lohr
Alex Lohr2y ago
Ah, I can't believe I missed that: destrucuring of props. This breaks reactivity. Try using props.viewState instead.
Mr Void
Mr VoidOP2y ago
PepeHands still same Login(props:any), props.viewState(false);
Alex Lohr
Alex Lohr2y ago
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
Mr Void
Mr VoidOP2y ago
whygod make sense PepeHands only thing I can think of is the return from App component
return (<>
{
store.user.loading ? <Loading /> :
store.user.isAuthenticated ? <Main /> :
<Auth />
}
</>);
return (<>
{
store.user.loading ? <Loading /> :
store.user.isAuthenticated ? <Main /> :
<Auth />
}
</>);
the following works :
return (
<Show when={store.user.loading} fallback={
<Show when={store.user.isAuthenticated} fallback={<Auth />}>
<Main />
</Show>
}>
<Loading />
</Show>
);
return (
<Show when={store.user.loading} fallback={
<Show when={store.user.isAuthenticated} fallback={<Auth />}>
<Main />
</Show>
}>
<Loading />
</Show>
);
is there a cleaner way of doing this?
Alex Lohr
Alex Lohr2y ago
Use a function to wrap the ternary.
Mr Void
Mr VoidOP2y ago
This works: ✅
<Switch fallback={<Auth />}>
<Match when={store.user.loading}>
<Loading />
</Match>
<Match when={store.user.isAuthenticated}>
<Main />
</Match>
</Switch>
<Switch fallback={<Auth />}>
<Match when={store.user.loading}>
<Loading />
</Match>
<Match when={store.user.isAuthenticated}>
<Main />
</Match>
</Switch>
Alex Lohr
Alex Lohr2y ago
That's even more idiomatic 🙏
Want results from more Discord servers?
Add your server