SolidJS State Management

Most of us used to handle state using popular libraries like mobix, redux and so on. SolidJS comes with great built-in capabilities for state management which we can utilize.

SolidJS State Management

Hey everyone. I really wanted to start using solid and the first thing I wanted to understand and the cover was state management.

Let's create a UserService , it will be responsible for the user state.

import { User } from "@typings/User"
import { onMount } from "solid-js";
import { createStore } from "solid-js/store"

const userStore = createStore<User>();

export const UserService = () => {
    const [user, setUser] = userStore
    
    onMount(() => {
        const userString = localStorage.getItem('user')
        if (!userString) return
        console.log('onMount')
        setUser(() => JSON.parse(userString) as unknown as User)
    })

    const updateUser = (user: User) => {
        setUser(() => user)
        localStorage.setItem('user', JSON.stringify(user))
    }


    return { user, updateUser }
}
UserService.tsx

As you can see we can use onMount on first render to preload our state from localStorage if it exists.
We expose the state itself and updateUser in our return value.
We can also expose methods for updating specific fields if we so wish.

Now I am going to create  a context which will serve as access to all services the control specific states which cannot be mutated outside of those services

import { createContext, ParentComponent, useContext } from "solid-js"
import { UserService } from "./services/UserService"


export type RootState = {
    userService: ReturnType<typeof UserService>
}


const rootState: RootState = {
    userService: UserService()
}

const StoreContext = createContext<RootState>()

export const useAppSelector = () => useContext(StoreContext)!

export const StoreProvider: ParentComponent = (props) => {
    return <StoreContext.Provider value={rootState}>{props.children}</StoreContext.Provider>
}

store.tsx

I have also defined a selector to retrieve the store context.
Now we need to use the provider for our context

/* @refresh reload */
import { render } from 'solid-js/web';
import { lazy } from "solid-js";

import './index.css';

import { ThemeProvider } from '@suid/material';
import { AppTheme } from '@shared/theme';
import { Router, Routes, Route, Link } from "solid-app-router";
import { StoreProvider } from '@shared/store';

const Login = lazy(() => import("./pages/login/Login"));
const App = lazy(() => import("./pages/app/Home"));


render(() => (
    <StoreProvider>
        <ThemeProvider theme={AppTheme}>
            <Router>
                <div id={'AppContainer'}>
                    <Routes>
                    	<Route path="/" element={<h1>Root</h1>} />
                        <Route path="/login" element={<Login />} />
                        <Route path="/app" element={<App />} />
                    </Routes>

                </div>
            </Router>
            
        </ThemeProvider>
    </StoreProvider>
)
    , document.getElementById('root') as HTMLElement);
index.tsx

I can then access the store from anywhere on my application

export default function Home() {
  const {userService:{ user }} = useAppSelector()

  return (
    <Box>
      <CodeBlock>
        {JSON.stringify(user,null,2)}
      </CodeBlock>
    </Box>
  )
}
 
Home.tsx

This is the best I came up with on a moment's notice and wanted to share.
Hope this is helpful for you :)