How do I best have createMemo in a store?

I'm used to MobX, where I can put a @computed on any method in a store. In Solid, how do I best replicate this? If I do this:
export class Chat {
state: ChatState
private setState: SetStoreFunction

isActive: () => boolean

constructor() {
const [state, setState] = createStore({
//...
})

this.state = state
this.setState = setState

// Create memo after state is initialized
this.isActive = createMemo(() => uiStore.state.activeDocumentID === this.state.uuid)
}
export class Chat {
state: ChatState
private setState: SetStoreFunction

isActive: () => boolean

constructor() {
const [state, setState] = createStore({
//...
})

this.state = state
this.setState = setState

// Create memo after state is initialized
this.isActive = createMemo(() => uiStore.state.activeDocumentID === this.state.uuid)
}
Then I get the error: computations created outside a createRoot or render will never be disposed I'd love to "cache" this value. There are thousands of documents and only one can be active at any time. How would you best structure the store for this, so that the comparisons cached/memoed?
6 Replies
Alex Lohr
Alex Lohr2w ago
It's totally fine to split your state into multiple references. In any case, your code looks like a prime use case for createSelector: https://docs.solidjs.com/reference/secondary-primitives/create-selector That being said, if you still want to put this inside your store, getters inside your stores will work. You will probably need to figure out circular dependencies.
hyperknot
hyperknotOP2w ago
So I could put createSelector in a store? I just need to make sure I init the store inside the root, right? I'm still trying to figure out why am I getting
computations created outside a createRoot or render will never be disposed
computations created outside a createRoot or render will never be disposed
even if I only call this function inside onMount
Alex Lohr
Alex Lohr2w ago
You need to wrap the creation of the store and any computations in a createRoot. Something like this:
export const [store, setStore] = createRoot(() => {
return [store, setStore] = createStore({
state: { activeDocumentId: null },
isActive: createSelector(() => store.state.activeDocumentId, (id, _) => id === store.state.uuid)
});
export const [store, setStore] = createRoot(() => {
return [store, setStore] = createStore({
state: { activeDocumentId: null },
isActive: createSelector(() => store.state.activeDocumentId, (id, _) => id === store.state.uuid)
});
hyperknot
hyperknotOP7d ago
and isn't it a problem to have a createRoot per store? I only have a few stores, so it's not a big number, but I was wondering if I should try to make everything in exactly one root. I mean, inside the render() function, without ever using createRoot. Or is there no point in limiting roots that much? I created a Stackblitz + GitHub repo for this. https://stackblitz.com/~/github.com/hyperknot/solidjs-sandbox My questions: 1. To avoid the root warning, I had to both move this function inside onMount: https://github.com/hyperknot/solidjs-sandbox/blob/a19b9581595bedd7b5e7949560a7b0d0755b8fd7/src/1-simple/App.jsx#L7 and wrap my store creating inside a createRoot: https://github.com/hyperknot/solidjs-sandbox/blob/a19b9581595bedd7b5e7949560a7b0d0755b8fd7/src/1-simple/store/uiStore.js#L26 Is this correct? I mean, why isn't one of these enough to solve the "computations created outside a createRoot or render will never be disposed" warning?
Alex Lohr
Alex Lohr7d ago
and isn't it a problem to have a createRoot per store?
It shouldn't be. createRoot just initializes a shared reactive context to which effects and computations can be subscribed and returns its output.
hyperknot
hyperknotOP7d ago
great, thanks!

Did you find this page helpful?