Hey folks, I'm new to Qwik and want to implement some really simple logic: Check for the item in the LocalStorage, and if the item exists - render the component, if not - redirect to '/abc' page. The only way that I've found for now is to use useVisibleTask but it's executed after the component has been rendered, and it causes flushing . Is there a way to check the local storage before the actual render?
#Check LocalStorage item before rendering the component
32 messages · Page 1 of 1 (latest)
Maybe it's against the Qwik philosophy, so I would be grateful for any help or guidelines
Yes, so useVisibleTask$ is similar to something like a useEffect in React where it is executed eagerly on the client. We want to use it very sparingly. One major difference though, is that it is executed only in the viewport unless you explicitly change the strategy. (This is still a major benefit over something like a useEffect)
What you're looking for is useTask$, this is done pre-render
https://qwik.builder.io/docs/components/tasks/#usetask
My guess is you want something like this
import { isBrowser } from '@builder.io/qwik/build';
import { useTask$ } from '@builder.io/qwik';
useTask$(() => {
if (isBrowser) {
const item = localStorage.getItem('yourItem');
if (!item) {
// do useNavigate instead for SPA navigation
window.location.href = '/abc';
}
}
});
But because this is done at pre-render, I believe you need an isBrowser conditional since to get something from localstorage I think it needs to be on the client.
A visible task might make sense here if useTask doesn't do the trick
A visible task is to be avoided whenever possible, because we are eagerly loading things. So yes it's an anti pattern, but in some cases it can't be avoided
Even then though, it is still a world of a difference better than the alternatives in other frameworks
https://www.dimension.dev/ for example uses a ton of visible tasks
Reply to: My guess is you want something like this
As far as I understand, the code above will never run in the browser(at least I've tried and nothing happened) the useTask runs only on the server side. Is there a way to say "Hey Qwik, please execute the following code ON BROWSER and BEFORE RENDER"
From what I understand no. You cannot do that in other frameworks either. It's the same thing with a React useEffect.
Could be that I'm wrong though
the useTask runs only on the server side.
An important distinction: the useTask$ is on the server until there is a tracked change, then it is on the client.
and that is when it is mpa page load
it is on the client already on spa page load
TLDR it looks like a visible task makes the most sense here
In React and Vue I can create some sort of HOC and check the localstorage in this HOC and basically make the redirect call in this Wrapper component, before actually rendering the Children
what is an hoc?
High ordered component, basically wrapper for any Component. ProtectedRouter as an example
If you can do it in React I doubt you couldn't do it in Qwik, but I don't understand because as soon as an effect is needed it's after rendering.
Visible task works fine, but because it's executed after render - I'm getting annoying flushing, not the end of the world, but could be better
Now I think you are right, it seems like the HOC approach should work fine in Qwik too, I probably need to read some more about the rendering mechanism in Qwik and try to figure out how to block the rendering of children components. Thanks for your help and time
Something to know is that with content projection in Qwik the parents don't actually know about their children.
You might be able to do something with an inline component if that becomes a problem
This is why things don't re-render if they don't have to.
They can even be rendered out of order
Yep, I think that is the answer that I was looking for. Indeed, I forgot about this feature and it was flushing because of the content projection and the inline components are actually the solution here(at least it seems like the solution) So thanks again, I will try this approach
@full palm is an inline component guru. He might be able to help if you're still stuck
😂
I was writing in Qwik using approaches from other framework, I need to focus more on Qwik philosophy and forget about all the React / Vue stuff
Have a nice day / night!
I found some workaround for this kind of problem, and it seems like it can be reused by any component. Basically I have created a ProtectedComponent that checks the value from localstorage and redirect to the another page if there is no such value. It might be a bad practice, but it's the only way(at least I didn't find another yet) to navigate from ComponentA to PageB without actually rendering the ComponentA. It works without "flushing"
export default component$(() => {
const awaitedForLocalStorageCheck = useSignal(false);
const naviage = useNavigate();
useVisibleTask$(() => {
const userId = getUserId();
if (!userId) {
naviage('/login');
} else {
awaitedForLocalStorageCheck.value = true;
}
});
if (awaitedForLocalStorageCheck.value) {
return <Slot />;
}
return null;
});
IMHO, when you're in an SPA app, and you're logged out, it should show a login modal on top of the page instead of redirecting. Then once login succeeds you refresh your data from the server and the modal disappears. That way you don't lose page state