0

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.

3
  • Can you please simulate the problem in JSFiddle or code-sandbox, so that we can solve it there directly. Commented Mar 19, 2022 at 5:46
  • do you mean that form only display input with Package Name field but not others? Commented Mar 19, 2022 at 5:47
  • Yes correct @sid Commented Mar 19, 2022 at 9:30

2 Answers 2

1

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,
}
...
Sign up to request clarification or add additional context in comments.

4 Comments

Thank you. I receive a "Uncaught TypeError: Cannot read properties of undefined (reading 'value')" when I update to onChange={e => setPackageInfo({...packageInfo, packageName: e.target.value})}. Any idea? Also tried onChange={e => setPackageInfo({...packageInfo, [packageName]: e.target.value})}. This happens when I'm typing on the textbox. The original problem of packageName field only populating even after using your suggested useEffect. Appreciate your help.
Upon checking @shopify/polaris docs, the TextField component takes a function with a value parameter, not event. I will edit my answer to reflect this. Also, the brackets on the fieldName were meant to show the value of a generic variable, meaning the name of the current field.
Thank you Kriss. This has sorted the error I mentioned. However, the original problem of packageName only being shown in the text box and not the others still exists. Any idea why this is happening?
Thanks sorted this out. Apparently, the module doesn't accept integer values. Converted it to a string and it worked. Thank you for the help again.
0

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.

1 Comment

Thank you. I receive a "Uncaught TypeError: Cannot read properties of undefined (reading 'value')" when I update to onChange={e => setPackageInfo({...packageInfo, packageName: e.target.value})}. Any idea? This happens when I'm typing on the textbox. The original problem of packageName field only populating even after using your suggested useEffect. Appreciate your help.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.