S
SolidJS•12mo ago
JCat 🎄

Using a function outside of components

Hi all, I've come across an interesting situation. I am currently doing a project using SolidJS. I have a hook (hello React) that handles authentication:
import { createSignal } from "solid-js";

export function useAuth() {
const [isLoaded, setIsLoaded] = createSignal(false);
const [isAuthed, setIsAuthed] = createSignal(false);

const signup = async (login, password) => { /* request... */ };

const login = async (login, password) => {
try {
/// axios request...
setIsAuthed(true);
} catch (error) {
// error handling
}
};

const refresh = async () => {
try {
// axios request...
setIsAuthed(true);
} catch (error) {}
setIsLoaded(true);
};

const logout = async () => {
try {
// axios request...
} catch (error) {}
setIsAuthed(false);
};

return {
register,
login,
refresh,
logout,
isAuthed,
isLoaded,
};
}
import { createSignal } from "solid-js";

export function useAuth() {
const [isLoaded, setIsLoaded] = createSignal(false);
const [isAuthed, setIsAuthed] = createSignal(false);

const signup = async (login, password) => { /* request... */ };

const login = async (login, password) => {
try {
/// axios request...
setIsAuthed(true);
} catch (error) {
// error handling
}
};

const refresh = async () => {
try {
// axios request...
setIsAuthed(true);
} catch (error) {}
setIsLoaded(true);
};

const logout = async () => {
try {
// axios request...
} catch (error) {}
setIsAuthed(false);
};

return {
register,
login,
refresh,
logout,
isAuthed,
isLoaded,
};
}
There is also a generic site template that has a check if the user is authorized or not to show the right menu items:
import { useNavigate } from "@solidjs/router";
import { useAuth } from "../hooks";

export default function Main({ children }) {
const { isAuthed, logout } = useAuth();
const navigate = useNavigate();

const doLogout = () => {
logout();
navigate("/");
};

return (
<>
<header className="flex items-center justify-between py-3">
<a href="/">
<img src="/logo.png" className="w-12" alt="Logo" />
</a>
{isAuthed() ? (
<nav className="flex items-center gap-4 p-4">
<a href="/profile">Profile</a>
<a href="#" onClick={doLogout}>
Sign out
</a>
</nav>
) : (
<nav className="flex items-center gap-4 p-4">
<a href="/login">Sign in</a>
<a href="/signup">Sign up</a>
</nav>
)}
</header>

<main className="h-[calc(100vh-(56px+1.5rem))]">{children}</main>
</>
);
}
import { useNavigate } from "@solidjs/router";
import { useAuth } from "../hooks";

export default function Main({ children }) {
const { isAuthed, logout } = useAuth();
const navigate = useNavigate();

const doLogout = () => {
logout();
navigate("/");
};

return (
<>
<header className="flex items-center justify-between py-3">
<a href="/">
<img src="/logo.png" className="w-12" alt="Logo" />
</a>
{isAuthed() ? (
<nav className="flex items-center gap-4 p-4">
<a href="/profile">Profile</a>
<a href="#" onClick={doLogout}>
Sign out
</a>
</nav>
) : (
<nav className="flex items-center gap-4 p-4">
<a href="/login">Sign in</a>
<a href="/signup">Sign up</a>
</nav>
)}
</header>

<main className="h-[calc(100vh-(56px+1.5rem))]">{children}</main>
</>
);
}
And also the login page itself which calls the login method:
import { useNavigate } from "@solidjs/router";
import { useAuth } from "../hooks/useAuth";
import { failure } from "../services";

export default function Login() {
const { login } = useAuth();
const navigate = useNavigate();

const submit = async (event) => {
event.preventDefault();

// ...
// A part of the code that is not important for this situation
// ...

if (await login(_login, password)) {
navigate("/");
}
};

return (
{ /* Stylized form with data submission in onSubmit */ }
);
}
import { useNavigate } from "@solidjs/router";
import { useAuth } from "../hooks/useAuth";
import { failure } from "../services";

export default function Login() {
const { login } = useAuth();
const navigate = useNavigate();

const submit = async (event) => {
event.preventDefault();

// ...
// A part of the code that is not important for this situation
// ...

if (await login(_login, password)) {
navigate("/");
}
};

return (
{ /* Stylized form with data submission in onSubmit */ }
);
}
So, the problem is that the state seems to change internally, but is not tracked externally (as if each component in which useAuth() is called has its own state of signals). I initially solved the problem by using createContext/useContext. Later I went to see if there is a state manager library for SolidJS, like Recoil for React. Not finding anything I decided to try to write a wrapper over createContext/useContext similar to Recoil. And what is interesting is that I accidentally noticed unusual behavior of createSingal, and in general all "hooks" in SolidJS. In React all useX functions (useState, useEffect, etc.) should be strictly used only in hooks, which is not the case in SolidJS. I.e. you can write the following code and it will work as it should:
import { createSignal } from "solid-js";

const [isLoaded, setIsLoaded] = createSignal(false);
const [isAuthed, setIsAuthed] = createSignal(false);

export function useAuth() {
// ...
}
import { createSignal } from "solid-js";

const [isLoaded, setIsLoaded] = createSignal(false);
const [isAuthed, setIsAuthed] = createSignal(false);

export function useAuth() {
// ...
}
I would like to know if this is considered normal practice in SolidJS, or should I not write this way to avoid bugs in the future?
4 Replies
Brendonovich
Brendonovich•12mo ago
Later I went to see if there is a state manager library for SolidJS, like Recoil for React
Solid's equivalent to React's state management libraries is pretty much just signals and stores, they work wherever you need
I would like to know if this is considered normal practice in SolidJS, or should I not write this way to avoid bugs in the future?
Nah it's fine, an example of using stores outside of components is actually part of the tutorial https://www.solidjs.com/tutorial/stores_nocontext
SolidJS
Solid is a purely reactive library. It was designed from the ground up with a reactive core. It's influenced by reactive principles developed by previous libraries.
JCat 🎄
JCat 🎄OP•12mo ago
Wow, that's true. I should probably read the rest of the textbook.
bigmistqke
bigmistqke•12mo ago
yes 🙂 welcome to solid, reactivity everywhere
bigmistqke
bigmistqke•12mo ago
https://www.youtube.com/watch?v=cELFZQAMdhQ is a good introduction to the basic concept of how its reactivity (and signals in general) work
SolidJS
YouTube
Intro to SolidJS reactivity (in 5 minutes)
An introduction video that walks you through Solid's reactivity in under 5 minutes.
Want results from more Discord servers?
Add your server