skip to Main Content

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 [height, setHeight] = useState('');
    const [width, setWidth] = useState('');
    const [depth, setDepth] = useState('');
    const [maxWeight, setMaxWeight] = useState('');
    const [packageName, setPackageName] = useState('');
    const [packageId, setPackageId] = useState(null);
    const [btnLoadingState, setBtnLoadingState] = useState(false);

    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(async () => {
        const data = await retrievePackage();
        console.log(data);
        setMaxWeight(data.maxWeight);
        setDepth(data.depth);
        setHeight(data.height);
        setWidth(data.width);
        setPackageName(data.packageName);
    }, [editPackageId]);

    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={packageName} onChange={setPackageName} autoComplete="off" />
                <TextField label="Height in CM" value={height} onChange={setHeight} autoComplete="off" />
                <TextField label="Width in CM"  value={width} onChange={setWidth} autoComplete="off" />
                <TextField label="Depth in CM"  value={depth} onChange={setDepth} autoComplete="off" />
                <TextField label="Max Weight in Grams"  value={maxWeight} onChange={setMaxWeight} 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.

2

Answers


  1. 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.

    Login or Signup to reply.
  2. It seems like the form has some internal state.
    Shopify has a package for managing form state: @shopify/react-form-state.

    For this example, if you want to keep it simple, make a state hook for every field. This is not slow since react groups setState calls in rerenders and if multiple requests are made, the page wont refresh depending on the field count but only once.

    const [packageName, setPackageName] = useState("");
    const [height, setHeight] = useState("");
    
    async function retrievePackage(){
      setIsLoading(true);
      const response = await axiosInstance.get('/packageInfo?packageId=' + editPackageId);
      setIsLoading(false);
      return response.data;
    }
    
    useEffect(() => {
      const data = await retrievePackage();
       
      setPackageName(data.packageName);
      setHeight(data.height);
      ...
    }, []);
    
    <TextField
      value={packageName}
      onChange={setPackageName}
    />
    <TextField
      value={height}
      onChange={setHeight}
    />
    

    Then submit the object composed from all the hooks

    const formData = {
      packageName,
      height,
    }
    ...
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search