skip to Main Content

I want to fetch data from the database and then populate it in the appropriate fields. Then I want to be able to edit them and save the changes. But, I am having several problems with the text fields.

An image of the field already populated:

This is the page I was working on

If I use something like this:

const [lname, setLname] = useState("");

<TextField
  fullWidth
  label="Last name"
  name="lname"
  required
  value = { `${userDetails.lname}` || "" }
  onChange={(e) => setLname(e.target.value)}
/>

Then the text field becomes read-only, which I think is due to the fact that once I use onChange, it populates the field again using the value which is kind of a constant here.

If I change the value to defaultValue, I am able to update the value, but the initial value is undefined.

If I use something like this:

const [lname, setLname] = useState(userDetails.lname);

<TextField
  fullWidth
  label="Last name"
  name="lname"
  required
  value = {lname}
  onChange={(e) => setLname(e.target.value)}
/>

The initial TextField becomes empty.

The UserDetails is populated like this:

export default function ProfileDetails() {
  
  const { user } = useContext(UserContext);
  const [userDetails, setUserDetails] = useState({});
  const { dispatch, isFetching } = useContext(UserContext);

  useEffect(() => {
    axios
      .get("http://localhost:42690/api/users/user-details", {
        headers: { Authorization: `Bearer ${user.token}` },
      })
      .then((res) => {
        console.log(res.data.fetchedUser);
        setUserDetails(
           (prevState) => ( { ...prevState, ...res.data.fetchedUser })
        );
      })
      .catch((err) => {
        toast.error("Failure to Load Profile");
      });
  }, []);

Can someone please help me solve this issue? Thanks!

2

Answers


  1. You have to add a useEffect to update your state when userDetails.lname value becomes available:

    const [lname, setLname] = useState(userDetails.lname);
    
    useEffect(() => {
      setLname(userDetails.lname);
    }, [userDetails.lname]);
    
    <TextField
      fullWidth
      label="Last name"
      name="lname"
      required
      value = {lname}
      onChange={(e) => setLname(e.target.value)}
    />
    
    Login or Signup to reply.
  2. Having different states, userDetails and lname (in case of last name) for one input, is not a good idea, and that’s what is causing your issue.
    I suggest you only use userDetails, and update it according to the input that’s being changed, as an example, like so:

    Notice the comments I added

    export default function ProfileDetails() {
      const { user } = useContext(UserContext);
      const [userDetails, setUserDetails] = useState({});
    
      useEffect(() => {
        // The code that fetches data and updates userDetails goes here
      }, []);
    
      // One change handler for all inputs
      const handleInputsChange = (e) => {
        setUserDetails({ ...userDetails, [e.target.name]: e.target.value });
      };
    
      return (
        <>
          <TextField
            fullWidth
            label="First name"
            name="fname"
            required
            value={userDetails.fname}
            onChange={handleInputsChange}
          />
          <TextField
            fullWidth
            label="Last name"
            name="lname"
            required
            value={userDetails.lname}
            onChange={handleInputsChange}
          />
        </>
      );
    }
    
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search