I have a piece of react JS code that is supposed to fetch data from an endpoint and populate a form from the data.
The main issue I'm having with is that it only populates the first field. It does not populate the rest.
The react component is as below
import React, { useState, useCallback, useEffect } from "react";
import { Page, Button, Stack, Card, Form, FormLayout, TextField, TextContainer, Modal, Toast, TextStyle, Loading } from "@shopify/polaris";
import axiosInstance from "../common/RequestHandler";
import { useParams } from 'react-router-dom';
import { useNavigate } from "react-router";
function EditPackages(){
const [errorToastActive, setErrorToastActive] = useState(false);
const [active, setActive] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [ packageInfo, setPackageInfo ] = useState({});
const [btnLoadingState, setBtnLoadingState] = useState(false);
const toggleErrorToastActive = useCallback(() => setErrorToastActive((errorToastActive) => !errorToastActive), []);
const errorToastMarkUp = errorToastActive ? (
<Toast content="Error in editing your package" error onDismiss={toggleErrorToastActive} />
) : null;
const params = useParams();
const editPackageId = params.editPackageId;
console.log("Edit Package ID -> ", editPackageId);
const navigate = useNavigate();
useEffect(() => {
getPackage();
}, [getPackage]);
const backToPackages = function (){
navigate('/app/packages');
}
const getPackage = useCallback(async () => {
setPackageInfo(await retrievePackage());
}, []);
async function retrievePackage(){
setIsLoading(true);
const resp1 = await axiosInstance.get('/packageInfo?packageId=' editPackageId);
setIsLoading(false);
return await resp1.data;
}
return (
<Page title="Edit Package" fullWidth>
{errorToastMarkUp}
<Form>
<FormLayout>
<TextField label="Package Name" value={packageInfo.packageName} onChange={ e=> setPackageInfo(e.target.value)} autoComplete="off" />
<TextField label="Height in CM" value={packageInfo.height} onChange={ e=> setPackageInfo(e.target.value)} autoComplete="off" />
<TextField label="Width in CM" type="number" value={packageInfo.width} onChange={ e=> setPackageInfo(e.target.value)} autoComplete="off" />
<TextField label="Depth in CM" type="number" value={packageInfo.depth} onChange={ e=> setPackageInfo(e.target.value)} autoComplete="off" />
<TextField label="Max Weight in Grams" type="number" value={packageInfo.maxWeight} onChange={ e=> setPackageInfo(e.target.value)} autoComplete="off" />
<Button submit>Submit</Button>
</FormLayout>
</Form>
</Page>
);
}
export default EditPackages;
The getPackage method is to retrieve the data from the endpoint and I'm expecting the setPackageInfo to set the state/values for the object.
I can confirm the API data is retrieved and to confuse me even more, it populates the textbox with packageInfo.packageName. But the rest, none. I'm sure the names match with the data retrieve as well.
For better understanding, below is my response from the endpoint.
{
"id": 25,
"mId": 1,
"height": 123,
"width": 35,
"depth": 3,
"maxWeight": 4566,
"created_at": "2022-02-18T21:13:47.000000Z",
"updated_at": "2022-02-18T21:13:47.000000Z",
"packageName": "Some random name"
}
Any help is greatly appreciate. I've been hitting my head on a brick wall for days with this problem. Thank you in advance.
CodePudding user response:
Change
onChange={e => setPackageInfo(e.target.value)}
to
onChange={e => setPackageInfo({...packageInfo, [fieldName]: e.target.value})}
I would personally use useEffect instead of useCallback since it's supposed to manage state changes.
useEffect(async () => {
const data = await retrievePackage();
setPackageInfo(data);
}, [editPackageId]);
CodePudding user response:
Your onChange method is incorrect, that's why you get an object in the response from axios, but once one of the onChange(s) runs, the state changes and you are left with the first field in the tree only and the other values become null/undefined.
Try changing the onChange method to - e=> setPackageInfo({...packageInfo, packageName: e.target.value})
for packageName, e=> setPackageInfo({...packageInfo, height: e.target.value})
for height, and so on.