Search code examples
javascriptnode.jsreactjsremix.run

Handling UI State in Remix.run


I am trying out remix and ohh boy.. I am stuck on creating a simple counter (clicking button increase count)

I guess I am not supposed to use the useState hook so I tried my luck with loader and action as I believe that this is where it should be handled in Remix

What I have on my component is:

export default function Game() {
    const counter = useLoaderData();

    return (
        <>
            <div>{counter}</div>
            <div>
                <Form method="post">
                    <button type="submit">click</button>
                </Form>
            </div>
        </>
    );
}

Server:

import { ActionFunction, LoaderFunction } from 'remix';

let counter: number = 0;

export const loader: LoaderFunction = async () => {
    console.log('game object!', counter);
    return counter;
};

export let action: ActionFunction = async ({ request, params }) => {
    console.log('[action] game object!', ++counter);
    return counter;
};

The code above will have counter always resetting to 0 on every click

Looked around some repositories and what I can find are those storing in Cookie/DB/SessionStorage etc, however what if I just want a simple state for my UI?


Solution

  • You are supposed to use useState for your client-side state in Remix.

    If you clone the remix repository and do a grep -r useState in the remix/examples/ folder, you will find many occurrences of it.

    For example you have a simple one in the Route modal example (in app/routes/invoices/$id/edit.tsx), being used for a form with controlled inputs.

    What Remix does is make it easier to communicate between the client and the server by colocating their codes for the same functionnality, and providing simple ways to perform that communication. This is useful if you need to communicate the data to your server. If it's not the case, then it's totally ok to keep that information only on the client.

    About server side rendering

    Remix also server-side renders the components by default. Which means that it executes your React code on the server to generate the HTML, and sends that with the JavaScript code. That way the browser can display it even before it executes the JavaScript to run the React code on the browser.

    This means that in case your code (or a third party library code you use) uses some browser API in you component, you may need to indicate not to server-side render that component.

    There is a Client only components example that demonstrates how to do that. It includes an example with a counter storing its value in the local storage of the browser.