reactivity works in vite dev but fails in vite build

Hi guys I am in in quite the rabbit hole and love a sanity check, I've tried multiple refactors, but the issue is my solids reactivity is not working... In both environments * I see the console.log printed every time the button is clicked * I can inspect the store in the console to confirm the data is in the right state In vite dev: * i see the correct state of open/closed in the <Show> component In vite build: * I do not see the correct state in the <Show> component (only the initial state) store.ts
type ClosableMenu = 'settings'
type SolidStoreState = {
user?: User
needsLogin: boolean
openMenus: Record<ClosableMenu, boolean> & { menuCount: number }
onLoad?: number
}
export const [solidStore, setSolidStore] = createStore<SolidStoreState>({
needsLogin: true,
openMenus: {
menuCount: 0,
settings: false
}
})
export const openMenu = (menu: ClosableMenu) => {
setSolidStore('openMenus', (openMenus) => ({
...openMenus,
menuCount: openMenus.menuCount + 1,
[menu]: true
}))
}
export const closeMenu = (menu: ClosableMenu) => {
setSolidStore('openMenus', (openMenus) => ({
...openMenus,
menuCount: openMenus.menuCount - 1,
[menu]: false
}))
}
export const toggleMenu = (menu: ClosableMenu) => (solidStore.openMenus[menu] ? closeMenu(menu) : openMenu(menu))
type ClosableMenu = 'settings'
type SolidStoreState = {
user?: User
needsLogin: boolean
openMenus: Record<ClosableMenu, boolean> & { menuCount: number }
onLoad?: number
}
export const [solidStore, setSolidStore] = createStore<SolidStoreState>({
needsLogin: true,
openMenus: {
menuCount: 0,
settings: false
}
})
export const openMenu = (menu: ClosableMenu) => {
setSolidStore('openMenus', (openMenus) => ({
...openMenus,
menuCount: openMenus.menuCount + 1,
[menu]: true
}))
}
export const closeMenu = (menu: ClosableMenu) => {
setSolidStore('openMenus', (openMenus) => ({
...openMenus,
menuCount: openMenus.menuCount - 1,
[menu]: false
}))
}
export const toggleMenu = (menu: ClosableMenu) => (solidStore.openMenus[menu] ? closeMenu(menu) : openMenu(menu))
app.tsx
const App = () => {
createEffect(() => {
console.log('app settings is', solidStore.openMenus.settings)
})
return (
<div class={styles.App}>
<header class={styles.header}>
<button onClick={() => toggleMenu('settings')}>Settings</button>
<Show
when={solidStore.openMenus.settings}
fallback={<h6>settings closed {solidStore.openMenus.settings.toString()}</h6>}
>
<h1>Settings open</h1>
</Show>
</header>
</div>
)
}
const App = () => {
createEffect(() => {
console.log('app settings is', solidStore.openMenus.settings)
})
return (
<div class={styles.App}>
<header class={styles.header}>
<button onClick={() => toggleMenu('settings')}>Settings</button>
<Show
when={solidStore.openMenus.settings}
fallback={<h6>settings closed {solidStore.openMenus.settings.toString()}</h6>}
>
<h1>Settings open</h1>
</Show>
</header>
</div>
)
}
This seems like a pretty fundamental issue, but just wondering if anyone had any ideas around this :hidethepain: is this a vite issue perhaps?
5 Replies
Some Afk Guy
Some Afk GuyOP7d ago
for all future searchers reactivity is wonky in routes i will post a summary when i fix this bug lol nope.mp3 my latest refactor i tried making signals out of each property, but it still doesnt work despit console logging
type MenuRenderer = {
component: JSX.Element
field: ClosableMenu
signal: Accessor<boolean>
setSignal: Setter<boolean>
}

const menus: MenuRenderer[] = [
{
component: <Settings />,
field: 'settings'
}
] as never

const Router: Component = () => {
menus.forEach((menu) => {
;[menu.signal, menu.setSignal] = createSignal(false)
})
createEffect(() => {
menus.forEach((menu) => {
if (menu.signal() != solidStore.openMenus[menu.field]) menu.setSignal(solidStore.openMenus[menu.field])
})
console.log('router outside: settings is', solidStore.openMenus.settings)
})
return (
{menus.map(
(menu) =>
<Show when={menu.signal()}>{menu.component}</Show>
)}
{/* one extra one just to be explicit still doesn't work */}
<Show when={menus[0].signal()}><Settings /></Show>
{/* one extra one using the explict store statestill doesn't work */}
<Show when={solidStore.openMenus.settings}><Settings /></Show>
)
type MenuRenderer = {
component: JSX.Element
field: ClosableMenu
signal: Accessor<boolean>
setSignal: Setter<boolean>
}

const menus: MenuRenderer[] = [
{
component: <Settings />,
field: 'settings'
}
] as never

const Router: Component = () => {
menus.forEach((menu) => {
;[menu.signal, menu.setSignal] = createSignal(false)
})
createEffect(() => {
menus.forEach((menu) => {
if (menu.signal() != solidStore.openMenus[menu.field]) menu.setSignal(solidStore.openMenus[menu.field])
})
console.log('router outside: settings is', solidStore.openMenus.settings)
})
return (
{menus.map(
(menu) =>
<Show when={menu.signal()}>{menu.component}</Show>
)}
{/* one extra one just to be explicit still doesn't work */}
<Show when={menus[0].signal()}><Settings /></Show>
{/* one extra one using the explict store statestill doesn't work */}
<Show when={solidStore.openMenus.settings}><Settings /></Show>
)
the solid never rerenders with the correct state perhaps this is an issue with my configuration of vite build... :Thinking3D:
peerreynders
peerreynders7d ago
One red flag:
type MenuRenderer = {
component: JSX.Element
field: ClosableMenu
signal: Accessor<boolean>
setSignal: Setter<boolean>
}
type MenuRenderer = {
component: JSX.Element
field: ClosableMenu
signal: Accessor<boolean>
setSignal: Setter<boolean>
}
I suspect that needs to be:
type MenuRenderer = {
component: () => JSX.Element
field: ClosableMenu
signal: Accessor<boolean>
setSignal: Setter<boolean>
}
type MenuRenderer = {
component: () => JSX.Element
field: ClosableMenu
signal: Accessor<boolean>
setSignal: Setter<boolean>
}
- React Components render ReactElements … over and over and over again. - Solid Components create DOM Elements (nested in an effect) exactly once to never run again. JSX.Element is the result from a component; () => JSX.Element is a "thunk" that creates that result when and where it is needed (like late binding). Also use <For> not .map inside component JSX.
peerreynders
peerreynders7d ago
My re-imagining of your first example: https://playground.solidjs.com/anonymous/1bb5ee67-d852-4fed-b828-1d200ef268bb The problem with creating the store as a module global is that it won't be created under a reactive root/owner. You likely want to create that store inside a Provider and then make the functions available via useContext
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
Some Afk Guy
Some Afk GuyOP6d ago
Thank you for the help @peerreynders :cheers: I have fiddled with your fiddle to more accurately represent my file structure. https://playground.solidjs.com/anonymous/27b4ad67-6edc-488d-95db-1f93410043ad One think i thing i think i am learning from this process is that the previous toggleMenu had the potential to cause reactivity issues
const toggleMenu = (menu: ClosableMenu) =>
(solidStore.openMenus[menu] ? closeMenu : openMenu)(menu);
const toggleMenu = (menu: ClosableMenu) =>
(solidStore.openMenus[menu] ? closeMenu : openMenu)(menu);
The linter was giving me warnings since solidStore.openMenus[menu] is being referenced as a dynamic value, but was not being created in a reactive context so could cause issues during the build? But despite my attempts at understanding whats going on, I could not get the window to show in the build version of the app. I think im gonna try to restart from a blank new vite project because the playground at least shows a POC that my approach should work.... I tried usingContext/memos and signals just to see all of these variants work, but never in build 😦
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
zulu
zulu6d ago
try updating the solid related packages to more recent version if not already doing that

Did you find this page helpful?