Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

❌ DEFAULT VALUES DON'T WORK ❌ #1967

Closed
aymanechaaba1 opened this issue Nov 17, 2023 · 13 comments
Closed

❌ DEFAULT VALUES DON'T WORK ❌ #1967

aymanechaaba1 opened this issue Nov 17, 2023 · 13 comments

Comments

@aymanechaaba1
Copy link

aymanechaaba1 commented Nov 17, 2023

'use client';

import { z } from 'zod';
import { Button } from './ui/button';
import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from './ui/form';
import {
  Sheet,
  SheetContent,
  SheetHeader,
  SheetTitle,
  SheetTrigger,
} from './ui/sheet';
import useCustomForm from '@/hooks/useCustomForm';
import { Checkbox } from './ui/checkbox';
import { trpc } from '@/app/_trpc/client';
import { useEffect, useState } from 'react';
import { serverClient } from '@/app/_trpc/serverClient';

function AssignStudents({
  teacher_id,
  students,
}: {
  teacher_id: string;

  students: Awaited<ReturnType<(typeof serverClient)['getStudents']>>;
}) {
  const utils = trpc.useUtils();

  const teacher = trpc.getTeacher.useQuery({
    id: teacher_id,
  });

  const items = [
    ...students.map((student) => ({
      id: student?.id,
      label: student?.firstname,
    })),
  ] as const;

  const FormSchema = z.object({
    items: z.array(z.string().cuid()),
  });

  const [defaultStudents, setDefaultStudents] = useState<string[] | undefined>(
    []
  );

  useEffect(() => {
    const ids = teacher.data?.students.map((student) => student.student_id);
    setDefaultStudents(ids);
  }, [teacher.data?.students]);

  const [openSheet, setOpenSheet] = useState(false);

  const [form] = useCustomForm({
    formSchema: FormSchema,
    defaultValues: {
      items: defaultStudents,
    },
  });

  const assignStudentToTeacher = trpc.assignStudentToTeacher.useMutation({
    onSuccess() {
      utils.getTeacher.invalidate();
    },
  });
  const deleteStudentFromTeacher = trpc.deleteStudentFromTeacher.useMutation({
    onSuccess() {
      utils.getTeacher.invalidate();
    },
  });

  async function onSubmit(data: z.infer<typeof FormSchema>) {
    // get checked values
    const checkedStudents = data.items;

    // get unchecked values
    const uncheckedStudents = students
      .filter((student, i) => {
        const sId = data.items[i];
        return sId !== student?.id;
      })
      .map((student) => student?.id);

    console.log(checkedStudents);
    console.log(uncheckedStudents);

    // setOpenSheet(false);
  }

  return (
    <Sheet open={openSheet} onOpenChange={setOpenSheet}>
      <SheetTrigger asChild>
        <Button variant="default">Assign Students</Button>
      </SheetTrigger>
      <SheetContent className="">
        <SheetHeader>
          <SheetTitle>Assign Students</SheetTitle>
        </SheetHeader>
        <Form {...form}>
          <form
            onSubmit={form.handleSubmit(onSubmit)}
            className="space-y-8 mt-5"
          >
            <FormField
              control={form.control}
              name="items"
              render={() => (
                <FormItem>
                  {items.map((student) => (
                    <FormField
                      key={student.id}
                      control={form.control}
                      name="items"
                      render={({ field }) => {
                        return (
                          <FormItem
                            key={student.id}
                            className="flex flex-row items-start space-x-3 space-y-0"
                          >
                            <FormControl>
                              <Checkbox
                                checked={field.value?.includes(student.id)}
                                onCheckedChange={(checked) => {
                                  return checked
                                    ? field.onChange([
                                        ...field.value,
                                        student.id,
                                      ])
                                    : field.onChange(
                                        field.value?.filter(
                                          (value: string) =>
                                            value !== student.id
                                        )
                                      );
                                }}
                              />
                            </FormControl>
                            <FormLabel className="font-normal">
                              {student.label}
                            </FormLabel>
                          </FormItem>
                        );
                      }}
                    />
                  ))}
                  <FormMessage />
                </FormItem>
              )}
            />
            <Button type="submit">Submit</Button>
          </form>
        </Form>
      </SheetContent>
    </Sheet>
  );
}

export default AssignStudents;
@aronedwards91
Copy link

May be worth checking what the first value passed for 'defaultStudents' is
defaults is cached on first render, caught me out also, fixed by firing a useEffect that triggers form.reset

eg:

  useEffect(() => {
    form.reset();
  }, [defaultStudents]);

@aymanechaaba1
Copy link
Author

@aronedwards91 When I write hard coded default values, it works, but with dynamic data, doesn't work

@aronedwards91
Copy link

Does sound like a cached value could be an issue, maybe provide .reset() with the new 'defaultValues' ?
https://react-hook-form.com/docs/useform/reset

@aymanechaaba1
Copy link
Author

@aronedwards91 which data is cached?

@aronedwards91
Copy link

Possibly the initial defaultValues
see this thread
#1361

@aymanechaaba1
Copy link
Author

@aronedwards91 they're talking about the select component, I'm dealing with a checkbox

@rexfordessilfie
Copy link

I have ran into a checkbox issue like this before but on a different UI library (Chakra), and I am not sure if it was specific to the UI library. In my case the checkbox was being controlled by a some condition based on user interactions somewhere else on the site - so not through a user manually clicking the checkbox.

My hack was to set the key of the checkbox to the toString() of the dynamic true or false value. Likely not the best/performant solution, but it may work for you!

@maykon-oliveira
Copy link

maykon-oliveira commented Nov 29, 2023

I'm facing the same problem. The input is of type text. The problem disappear when I provide a default Values, but it's very awful in a big form.

@aymanechaaba1 how did you deal with it?

@jackypan1989
Copy link

I got this problem, too.

@0Chan-smc
Copy link

Is this problem still going on? I think this is critical issue.

@aymanechaaba1
Copy link
Author

@jackypan1989 @0Chan-smc That works for me now

@NatanCieplinski
Copy link

This issue is related to how you are using react-hook-form, and not the component library.

defaultValues are cached, and need to be manually set if you want to change them, as you can read in their docs

@aymanechaaba1
Copy link
Author

@NatanCieplinski You're right, the issue is a react-hook-form issue, and default values need to be defined.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants