I am trying to create a remix page where i want to get live preview when i change a Select
tag. It is going through a Form since i want it to translate the data.
A solution to my problem could be to make preventDefault
(first code example) to work or to find a way to make useActionData()
(second code example) to work when using useFetcher
With this code, the preventDefault
does not work. I need preventDefault
to work so that the selector doesn't reset. I could make the action function also send the name so that the DefaultValue in select is imported from action function, but this is going to become a big form and i dont want to refresh the whole page.
export async function action({ request }: ActionArgs) {
const form = new URLSearchParams(await request.text())
const name = form.get('name');
console.log('name', name);
return json({ message: name ? `Hello ${name}!` : 'Select name' });
}
export default function Page() {
const actionData = useActionData();
console.log('actionData', actionData);
return (
<>
<Form method="post">
<h1>{actionData ? actionData.message : 'Select name.'}</h1>
<select
name="name"
onChange={e => {
e.preventDefault();
e.target.form.submit();
}}
>
<option value="name 1">Name 1</option>
<option value="name 2">Name 2</option>
<option value="name 3">Name 3</option>
</select>
<button type="submit" className="bg-blue-500 text-white font-bold py-2 px-4">
Submit
</button>
</Form>
</>
);
}
I have also tried following https://github.com/remix-run/remix/issues/1807 using useRef and useFetcher
, but even tho the action function runs, it gives me undefined
when logging actionData.
export async function action({ request }: ActionArgs) {
const form = new URLSearchParams(await request.text())
const name = form.get('name');
console.log('name', name);
return json({ message: name ? `Hello ${name}!` : 'Select name' });
}
export default function Page() {
const actionData = useActionData();
console.log('actionData', actionData); // Gives undefined
const formRef = useRef<HTMLFormElement>(null);
const fetcher = useFetcher();
return (
<>
<fetcher.Form method="post" ref={formRef}>
<h1>{actionData ? actionData.message : 'Select name.'}</h1>
<select
name="name"
onChange={() => {
fetcher.submit(formRef.current);
}}
>
<option value="name 1">Name 1</option>
<option value="name 2">Name 2</option>
<option value="name 3">Name 3</option>
</select>
<button type="submit" className="bg-blue-500 text-white font-bold py-2 px-4">
Submit
</button>
</fetcher.Form >
</>
);
}
I found a solution, it was to use fetcher.load, and then have it as a own loader file.
Main file test.tsx:
import { useFetcher } from '@remix-run/react';
export default function Page() {
const fetcher = useFetcher();
return (
<>
<div>
<h1>{fetcher.data ? fetcher.data.message : 'Select name.'}</h1>
<select
name="name"
onChange={e => {
fetcher.load(`loader/?name=${e.target.value}`);
}}
>
<option value="name 1">Name 1</option>
<option value="name 2">Name 2</option>
<option value="name 3">Name 3</option>
</select>
<button type="submit" className="bg-blue-500 text-white font-bold py-2 px-4">
Submit
</button>
</div>
</>
);
}
Loaderfile loader.ts:
import type { LoaderArgs } from '@remix-run/node';
import { json } from '@remix-run/node';
export async function loader({ request }: LoaderArgs) {
const form = new URLSearchParams(await request.text());
const name = form.get('name');
return json({ message: name ? `Hello ${name}!` : 'Select name' });
}