S
SolidJS•3y ago
Song

how to`createStore` and using `createEffect` to persist without warning

I want to create a function to persist the store to the localstorage, everything works, but it warns that computations created outside a createRoot or render will never be disposed. I have tried to move createEffect outside onMounted, but it even warn twice. Additionally, moving onMounted inside provider makes persist break. No help using ChatGPT🄲. Does anyone know how to solve it? here is my code
export function persistStore< T extends object = {}, R extends ActionReturn = {}>(
name: string,
options: StoreOption<T, R>,
): [provider: ParentComponent, useStore: () => BaseStore<T, R>] {
const { action, state, persist: persistOption } = options
const initalState = typeof state === 'function' ? state() : state
const [store, setStore] = createStore<T>(initalState, { name })

const ctxData = { store, ...action(setStore) }
const ctx = createContext(ctxData, { name: `ctx_${name}` })
const option = normalizePersistOption(name, persistOption)
onMount(() => {
if (!option) {
return
}
const { debug, key, serializer: { deserialize, serialize }, storage } = option
const stored = storage.getItem(key)
try {
if (stored) {
setStore(deserialize(stored))
debug && console.log(`[$store - ${key}]: read from persisted, value: ${stored}`)
} else {
storage.setItem(option.key, serialize(store))
debug && console.log(`[$store - ${key}]: no persisted data, initialize`)
}
} catch (e) {
debug && console.error(`[$store - ${key}]: ${e}`)
}
createEffect(on(() => deepTrack(store), () => {
debug && console.log(`[$store - ${key}]: update to ${JSON.stringify(store)}`)
storage.setItem(option.key, serialize(unwrap(store)))
}))
})
return [
(props: ParentProps): JSX.Element =>
createComponent(ctx.Provider, {
value: ctxData,
get children() {
return props.children
},
}),
() => useContext(ctx),
]
}
export function persistStore< T extends object = {}, R extends ActionReturn = {}>(
name: string,
options: StoreOption<T, R>,
): [provider: ParentComponent, useStore: () => BaseStore<T, R>] {
const { action, state, persist: persistOption } = options
const initalState = typeof state === 'function' ? state() : state
const [store, setStore] = createStore<T>(initalState, { name })

const ctxData = { store, ...action(setStore) }
const ctx = createContext(ctxData, { name: `ctx_${name}` })
const option = normalizePersistOption(name, persistOption)
onMount(() => {
if (!option) {
return
}
const { debug, key, serializer: { deserialize, serialize }, storage } = option
const stored = storage.getItem(key)
try {
if (stored) {
setStore(deserialize(stored))
debug && console.log(`[$store - ${key}]: read from persisted, value: ${stored}`)
} else {
storage.setItem(option.key, serialize(store))
debug && console.log(`[$store - ${key}]: no persisted data, initialize`)
}
} catch (e) {
debug && console.error(`[$store - ${key}]: ${e}`)
}
createEffect(on(() => deepTrack(store), () => {
debug && console.log(`[$store - ${key}]: update to ${JSON.stringify(store)}`)
storage.setItem(option.key, serialize(unwrap(store)))
}))
})
return [
(props: ParentProps): JSX.Element =>
createComponent(ctx.Provider, {
value: ctxData,
get children() {
return props.children
},
}),
() => useContext(ctx),
]
}
1 Reply
Song
SongOP•3y ago
well, I finally struggly solve it my self. According to https://github.com/solidjs-community/solid-primitives/blob/main/packages/context/src/index.ts, wrap onMount with a function and call it in createComponent, and all works without warn

Did you find this page helpful?