Back

Technologies:

javascriptjavascript
reactjsreactjs
avatar
Tolerim
a month ago

The inputs I populated with fetched data are not updating when changed - can you help troubleshoot?

My goal is to retrieve user data from a database and display it in appropriate fields. I also need to allow users to edit their information and save any changes made. Unfortunately, I've encountered some difficulties with text fields.

Below is an image of the field, already populated:

Screenshot of populated input field

After trying out a solution like this:

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

<TextField
  fullWidth
  label="Last name"
  name="lname"
  required
  value = { `${userDetails.lname}` || "" }
  onChange={(e) => setLname(e.target.value)}
/>
The text field became read-only, possibly because the value is constant due to the usage of onChange.

Alternatively, changing value to defaultValue allowed me to update the value, but the initial value became undefined.

Another potential solution, using the code below:

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

<TextField
  fullWidth
  label="Last name"
  name="lname"
  required
  value = {lname}
  onChange={(e) => setLname(e.target.value)}
/>
resulted in the initial TextField being empty.

UserDetails is populated in the following manner:

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");
      });
  }, []);
Would appreciate any assistance in resolving this issue. Thank you!

Answers(2)
avatar
Vogi
a month ago
Verified Answer
It seems that the issue you are facing is due to the fact that the value is constant due to the usage of onChange. One solution is to use defaultValue instead of value, which allows you to update the value but the initial value becomes undefined. Another solution is to use useState as shown in your code snippet. However, this resulted in the initial TextField being empty. You can try using a combination of both solutions by setting the initial state of your useState hook to an empty string and then using defaultValue instead of value. This should allow you to update the value and also display the initial value correctly. Here's an example:

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

<TextField
  fullWidth
  label="Last name"
  name="lname"
  required
  defaultValue={userDetails.lname}
  onChange={(e) => setLname(e.target.value)}
/>
I hope this helps! Let me know if you have any other questions.

Sources

【React】onChangeで値を取得する方法 - Qiitajavascript - React Material UI TextField onchange handler continue ...Unformatted value (or floatValue) within onChange #264 - Githubjavascript - React: TextField onchange - Stack OverflowHow to set useState const to value of input on changeTextField onChange, only value is passed #83 - Github
avatar
Tolerim
a month ago
It seems like you are having trouble populating the initial value of a TextField in React. The issue is that you are trying to populate the value before the userDetails state has been initialized. Here are some ways to solve this issue: 1. Wait for userDetails state to be populated before rendering the TextField. You can do this by conditionally rendering the TextField only after userDetails state has been initialized. You can make use of a spinner or a loading component to indicate to the user that the data is being loaded. Here's an example:
const [lname, setLname] = useState("");

{userDetails.lname ? (
  <TextField
    fullWidth
    label="Last name"
    name="lname"
    required
    value={lname}
    onChange={(e) => setLname(e.target.value)}
  />
) : (
  <Spinner />
)}
In this example, we are only rendering the TextField after userDetails.lname is truthy. Otherwise, we are displaying a Spinner component to indicate that the data is being loaded. 2. Initialize the lname state using userDetails.lname only after userDetails state has been initialized. You can do this by using another effect hook that updates the lname state whenever userDetails state changes. Here's an example:
const [lname, setLname] = useState("");

useEffect(() => {
  if (userDetails.lname) {
    setLname(userDetails.lname);
  }
}, [userDetails.lname]);
In this example, we are initializing the lname state using userDetails.lname only after userDetails state has been initialized. We are achieving this by using an effect hook that updates the lname state whenever userDetails.lname changes. Either of these approaches should solve your issue. Let me know if you have any other questions!
;