Home > Blockchain >  How to setValue value in useFormHook to form on re render in function component
How to setValue value in useFormHook to form on re render in function component

Time:10-27

I am creating a project where we can add and edit a user. For editing a user I am sending id as a url parameter using react-router-dom Link from one page to other and with the useParams hook. I am fetching that id. This id I am using for setting the data to form. I have all users stored in redux store. Now the question is when I reload the page the data is taking some time to load from redux store and the setValue of useFormHook is throwing an error.

import React, { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { useSelector } from "react-redux";
import { useParams } from "react-router-dom";
import { fetchData } from "./utils/index";
import { UpdateStudent} from "./utils/index";
function Update() {
  const users = useSelector((state) => state.students);
  console.log(users);
  const [students, setStudents] = useState([]);
  const {
    register,
    handleSubmit,
    setValue,
    formState: { errors, isDirty, isValid },
  } = useForm({ mode: "onChange" });
  let { id } = useParams();
  var user = students && students.filter((u) => u.id === parseInt(id));
  useEffect(() => {
    fetchData();
  }, []);

  useEffect(() => {
    setStudents(users);
  }, [users]);



useEffect(() => {
    setValue("name", user.name);
  }, []);
  const onUpdate = (data) => {
   
  };

  return (
            <form onSubmit={handleSubmit(onUpdate)}>
              <div>
                <input
                  {...register("name", {
                  })}
                  type="text"
                  className="form-control"
                  placeholder="Name"
             
                />
              </div>
                <button
                  color="primary"
                  type="submit"
                  disabled={!isDirty || !isValid}
                >
                  Save
                </button>
              
            </form>
         
  );
}

export default Update;

CodePudding user response:

The way I solve this in my current project is that I split the component into 2, one component gets the user, one is only rendered when the user is available.

function Update() {
  const users = useSelector((state) => state.students);
  console.log(users);
  const [students, setStudents] = useState([]);
  let { id } = useParams();
  var user = students && students.filter((u) => u.id === parseInt(id));
  useEffect(() => {
    fetchData();
  }, []);

  useEffect(() => {
    setStudents(users);
  }, [users]);

  if(!user) return null; // or progress indicator

  return <UpdateForm user={user} />
}


function UpdateForm({user})
  const {
    register,
    handleSubmit,
    setValue,
    formState: { errors, isDirty, isValid },
  } = useForm({ mode: "onChange" });
  
  useEffect(() => {
      setValue("name", user.name);
    }, []);
    const onUpdate = (data) => {
     
    };
  }, [user.name]);

  return (
            <form onSubmit={handleSubmit(onUpdate)}>
              <div>
                <input
                  {...register("name", {
                  })}
                  type="text"
                  className="form-control"
                  placeholder="Name"
             
                />
              </div>
                <button
                  color="primary"
                  type="submit"
                  disabled={!isDirty || !isValid}
                >
                  Save
                </button>
              
            </form>
         
  );
}

export default Update;

CodePudding user response:

Besides the issues I mentioned in comment above, the code doesn't handle when the students state updates. You could simplify the code a bit and consume the students state directly instead of duplicating it locally. Since the redux state is sometimes not available on the initial render cycle you'll need to use an useEffect with a dependency on the state used to update form state.

function Update() {
  const users = useSelector((state) => state.students);
  
  const {
    register,
    handleSubmit,
    setValue,
    formState: { errors, isDirty, isValid },
  } = useForm({ mode: "onChange" });

  const { id } = useParams();

  useEffect(() => {
    fetchData();
  }, []);

  useEffect(() => {
    const user = users?.filter((u) => u.id === Number(id));
    if (user) {
      setValue("name", user.name);
    }
  }, [users]); // <-- add users to dependency to update form state

  ...

  if (/* no form state yet */) {
    return "Loading..."; // or some loading indicator
  }

  return (
    ... // form UI
  );
}
  • Related