ashfaqrafi
ashfaqrafi

Reputation: 500

state data can not be set using useState in reactjs

I have a react component

import React from "react";
import { AgreementInfo } from "../../../../models/shop";
import { MdClose } from "react-icons/md";
import moment from "moment";
import { uploadImageCore } from "utils/image";

type AgreementInfoProps = {
  setFieldValue(agreement_code: string, val: AgreementInfo[]): void;
  kps: AgreementInfo[];
  index: number;
  kp: AgreementInfo;
};

export const Agreement = ({
  setFieldValue,
  kps,
  index,
  kp,
}: AgreementInfoProps): JSX.Element => {
  const [agreementCopy, setAgreementCopy] = React.useState("");

  const handleImageChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
    console.log(e.currentTarget.files);
    const files = e.currentTarget.files ?? "";
    console.log({ files });
    const res = await uploadImageCore(files[0]);
    console.log({ res });
    const agreementInfos = [...kps];
    console.log({ agreementInfos });
    const newCopy = setAgreementCopy(res.data.data.url);
    console.log({ agreementCopy });
    console.log({ newCopy });
    agreementInfos[index].agreement_scan_copy = agreementCopy;
    setFieldValue("agreement_info", [...agreementInfos]);
  };

  return (
    <>
      <div className="grid grid-cols-2 gap-4 w-full">
        <div>
          <label className="block mr-4">
            <input
              placeholder="Agreement code"
              value={kp.agreement_code}
              className="block w-full form-input"
              onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
                const agreementInfos = [...kps];
                agreementInfos[index].agreement_code = e.target.value;
                setFieldValue("agreement_info", [...agreementInfos]);
              }}
            />
          </label>
        </div>

        <div>
          <label className="block mr-4">
            <input
              className="block w-full form-input"
              onChange={(e) => handleImageChange(e)}
              type="file"
            />
          </label>
        </div>

        <div>
          <label className="block">
            <input
              placeholder="Agreement Expairy Date"
              onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
                const agreementInfos = [...kps];
                agreementInfos[index].agreement_expiry_date = e.target.value;
                setFieldValue("agreement_info", [...agreementInfos]);
              }}
              type="date"
              value={moment(kp.agreement_expiry_date).format("YYYY-MM-DD")}
              className="block w-full form-input"
            />
          </label>
        </div>

        <div>
          <label className="block mr-4">
            <input
              placeholder="Credit Limit"
              value={kp.credit_limit}
              className="block w-full form-input"
              onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
                const agreementInfos = [...kps];
                agreementInfos[index].credit_limit = parseInt(e.target.value);
                setFieldValue("agreement_info", [...agreementInfos]);
              }}
            />
          </label>
        </div>

        <div>
          <label className="block mr-4">
            <input
              placeholder="Credit Time"
              value={kp.credit_time}
              className="block w-full form-input"
              onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
                const agreementInfos = [...kps];
                agreementInfos[index].credit_time = parseInt(e.target.value);
                setFieldValue("agreement_info", [...agreementInfos]);
              }}
            />
          </label>
        </div>
      </div>

      <button
        type="button"
        onClick={() =>
          setFieldValue(
            "agreement_info",
            kps.filter((_, kpIndex: number) => kpIndex !== index)
          )
        }
        className="p-2 ml-4 text-gray-500 rounded-full hover:bg-gray-600 hover:text-white"
      >
        <MdClose />
      </button>
    </>
  );
};

I want to set data of agreement_scan_copy in the state agreementCopy. But I can not pass the data in this current implementation. This Agreement component will be used to show data in the form of an Array in another component. This is the component

import { FormikProps, FormikValues, Field } from "formik";
import "styled-components/macro";
import { KeyPerson } from "../../../../shop/component/create/KeyPerson";
import { Acquisition } from "../../../../shop/component/create/Acquisition";
import { Agreement } from "../../../../shop/component/create/Agreement";
import { CategoryHead } from "../../../../shop/component/create/CategoryHead";
import { BDM } from "../../../../shop/component/create/BDM";
import { KAM } from "../../../../shop/component/create/KAM";
import { VM } from "../../../../shop/component/create/VM";

export const inputClass =
  "rounded bg-gray-100 px-2 py-2 focus:bg-white border border-gray-100 focus:border-black block w-full";

export default function AdditionalInformations({
  formikBag,
}: {
  formikBag: FormikProps<FormikValues>;
}): JSX.Element {
  return (
    <div className="py-10 px-6">
      <div className="flex flex-row justify-between">
        <div className="mb-6">
          <>
            <div className="grid grid-cols-2 gap-4 w-full">
              <div className="mb-6">
                <label htmlFor={"organisation_type"}>
                  {"Organization Type"}
                </label>
                <Field
                  as="select"
                  name="organisation_type"
                  className="form-select"
                >
                  <option value="small">Small</option>
                  <option value="medium">Medium</option>
                  <option value="large">Large</option>
                </Field>
              </div>
              <div className="mb-6">
                <label htmlFor={"bin_no"}>{"BIN No"}</label>
                <Field
                  type="number"
                  name="bin_no"
                  id="bin_no"
                  className={"form-input"}
                />
              </div>
              <div className="mb-6">
                <label htmlFor={"trade_license_no"}>{"Trade License No"}</label>
                <Field
                  type="text"
                  name="trade_license_no"
                  id="trade_license_no"
                  className={"form-input"}
                />
              </div>
            </div>

            <div className="block mb-6">
              <p className="mb-2">
                Key Personnel
                <button
                  type="button"
                  onClick={() =>
                    formikBag.setFieldValue("key_personnel", [
                      ...formikBag.values.key_personnel,
                      {
                        username: "",
                        designation: "",
                        phone_no: "",
                        email: "",
                      },
                    ])
                  }
                  className="float-right ml-4 text-sm underline"
                >
                  Add Key Personnel
                </button>
              </p>
              {formikBag.values.key_personnel.map(
                (
                  kp: {
                    username: string;
                    designation: string;
                    phone_no: string;
                    email: string;
                  },
                  index: number
                ) => (
                  <div
                    key={index}
                    className="flex items-center p-4 mt-2 bg-gray-100 rounded"
                  >
                    <KeyPerson
                      setFieldValue={formikBag.setFieldValue}
                      kps={formikBag.values.key_personnel}
                      index={index}
                      kp={kp}
                    />
                  </div>
                )
              )}
            </div>

            <div className="grid grid-cols-2 gap-4 w-full">
              <div className="block mb-6">
                <p className="mb-2">
                  <b>Category Head</b>
                  <button
                    type="button"
                    onClick={() =>
                      formikBag.setFieldValue("category_head", [
                        ...formikBag.values.category_head,
                        {
                          username: "",
                        },
                      ])
                    }
                    className="float-right ml-4 text-sm underline"
                  >
                    Add Category Head
                  </button>
                </p>
                {formikBag.values.category_head.map(
                  (
                    ch: {
                      username: string;
                    },
                    index: number
                  ) => (
                    <div
                      key={index}
                      className="flex items-center p-4 mt-2 bg-gray-100 rounded"
                    >
                      <CategoryHead
                        setFieldValue={formikBag.setFieldValue}
                        chs={formikBag.values.category_head}
                        index={index}
                        ch={ch}
                      />
                    </div>
                  )
                )}
              </div>
              <div className="block mb-6">
                <p className="mb-2">
                  <b>BDM</b>
                  <button
                    type="button"
                    onClick={() =>
                      formikBag.setFieldValue("bdm", [
                        ...formikBag.values.bdm,
                        {
                          username: "",
                        },
                      ])
                    }
                    className="float-right ml-4 text-sm underline"
                  >
                    Add BDM
                  </button>
                </p>
                {formikBag.values.bdm.map(
                  (
                    bdm: {
                      username: string;
                    },
                    index: number
                  ) => (
                    <div
                      key={index}
                      className="flex items-center p-4 mt-2 bg-gray-100 rounded"
                    >
                      <BDM
                        setFieldValue={formikBag.setFieldValue}
                        bdms={formikBag.values.bdm}
                        index={index}
                        bdm={bdm}
                      />
                    </div>
                  )
                )}
              </div>
              <div className="block mb-6">
                <p className="mb-2">
                  <b>KAM</b>
                  <button
                    type="button"
                    onClick={() =>
                      formikBag.setFieldValue("kam", [
                        ...formikBag.values.kam,
                        {
                          username: "",
                        },
                      ])
                    }
                    className="float-right ml-4 text-sm underline"
                  >
                    Add KAM
                  </button>
                </p>
                {formikBag.values.kam.map(
                  (
                    kam: {
                      username: string;
                    },
                    index: number
                  ) => (
                    <div
                      key={index}
                      className="flex items-center p-4 mt-2 bg-gray-100 rounded"
                    >
                      <KAM
                        setFieldValue={formikBag.setFieldValue}
                        kams={formikBag.values.kam}
                        index={index}
                        kam={kam}
                      />
                    </div>
                  )
                )}
              </div>
              <div className="block mb-6">
                <p className="mb-2">
                  <b>VM</b>
                  <button
                    type="button"
                    onClick={() =>
                      formikBag.setFieldValue("vm", [
                        ...formikBag.values.vm,
                        {
                          username: "",
                        },
                      ])
                    }
                    className="float-right ml-4 text-sm underline"
                  >
                    Add VM
                  </button>
                </p>
                {formikBag.values.vm.map(
                  (
                    vm: {
                      username: string;
                    },
                    index: number
                  ) => (
                    <div
                      key={index}
                      className="flex items-center p-4 mt-2 bg-gray-100 rounded"
                    >
                      <VM
                        setFieldValue={formikBag.setFieldValue}
                        vms={formikBag.values.vm}
                        index={index}
                        vm={vm}
                      />
                    </div>
                  )
                )}
              </div>
            </div>

            <div className="block mb-6">
              <p className="mb-2">
                Acquisition Info
                <button
                  type="button"
                  onClick={() =>
                    formikBag.setFieldValue("acquisition_info", [
                      ...formikBag.values.acquisition_info,
                      {
                        acquisition_code: "",
                        acquisition_by: "",
                        acquisition_phone_no: "",
                        acquisition_email: "",
                        acquisition_date: "",
                      },
                    ])
                  }
                  className="float-right ml-4 text-sm underline"
                >
                  Add Acquisition Info
                </button>
              </p>
              {formikBag.values.acquisition_info.map(
                (
                  kp: {
                    acquisition_code: string;
                    acquisition_by: string;
                    acquisition_phone_no: string;
                    acquisition_email: string;
                    acquisition_date: string;
                  },
                  index: number
                ) => (
                  <div
                    key={index}
                    className="flex items-center p-4 mt-2 bg-gray-100 rounded"
                  >
                    <Acquisition
                      setFieldValue={formikBag.setFieldValue}
                      kps={formikBag.values.acquisition_info}
                      index={index}
                      kp={kp}
                    />
                  </div>
                )
              )}
            </div>

            <div className="block mb-6">
              <p className="mb-2">
                Agreement Info
                <button
                  type="button"
                  onClick={() =>
                    formikBag.setFieldValue("agreement_info", [
                      ...formikBag.values.agreement_info,
                      {
                        agreement_code: "",
                        agreement_scan_copy: "",
                        agreement_expiry_date: "",
                        credit_limit: "",
                        credit_time: "",
                      },
                    ])
                  }
                  className="float-right ml-4 text-sm underline"
                >
                  Add Agreement Info
                </button>
              </p>
              {formikBag.values.agreement_info.map(
                (
                  kp: {
                    agreement_code: string;
                    agreement_scan_copy: string;
                    agreement_expiry_date: string;
                    credit_limit: number;
                    credit_time: number;
                  },
                  index: number
                ) => (
                  <div
                    key={index}
                    className="flex items-center p-4 mt-2 bg-gray-100 rounded"
                  >
                    <Agreement
                      setFieldValue={formikBag.setFieldValue}
                      kps={formikBag.values.agreement_info}
                      index={index}
                      kp={kp}
                    />
                  </div>
                )
              )}
            </div>

            <div className="grid grid-cols-2 gap-4 w-full">
              <div>
                <label htmlFor={"bank_account_name"}>
                  {"Bank Account Name"}
                </label>
                <Field
                  type="text"
                  name="bank_account_name"
                  id="bank_account_name"
                  className={"form-input"}
                />
              </div>

              <div>
                <label htmlFor={"bank_account_no"}>{"Bank Account No"}</label>
                <Field
                  type="number"
                  name="bank_account_no"
                  id="bank_account_no"
                  className={"form-input"}
                />
              </div>

              <div>
                <label htmlFor={"bank_name"}>{"Bank Name"}</label>
                <Field
                  type="text"
                  name="bank_name"
                  id="bank_name"
                  className={"form-input"}
                />
              </div>

              <div>
                <label htmlFor={"bank_branch_name"}>{"Bank Branch Name"}</label>
                <Field
                  type="text"
                  name="bank_branch_name"
                  id="bank_branch_name"
                  className={"form-input"}
                />
              </div>

              <div>
                <label htmlFor={"bank_branch_routing_no"}>
                  {"Bank Branch Routing No"}
                </label>
                <Field
                  type="number"
                  name="bank_branch_routing_no"
                  id="bank_branch_routing_no"
                  className={"form-input"}
                />
              </div>

              <div>
                <label htmlFor={"sbu_unit"}>{"SBU Unit"}</label>
                <Field
                  type="text"
                  name="sbu_unit"
                  id="sbu_unit"
                  className={"form-input"}
                />
              </div>
            </div>
          </>
        </div>
      </div>
    </div>
  );
}

So the data structure of the Agreement Array is

{
  agreement_code: "",
  agreement_scan_copy: "",
  agreement_expiry_date: "",
  credit_limit: "",
  credit_time: "",
}

so now I want to set the data in the agreement_scan_copy key from the Agreement component and then POST in an API. But the above code does not set the value in the array. These are the console logs

FileList {0: File, length: 1}
0: File
lastModified: 1618304176889
lastModifiedDate: Tue Apr 13 2021 14:56:16 GMT+0600 (Bangladesh Standard Time) {}
name: "ehealth.png"
size: 4276
type: "image/png"
webkitRelativePath: ""
__proto__: File
length: 1
__proto__: FileList

res:
config: {url: "https://api-dev.evaly.com.bd/core/image/upload", method: "post", data: FormData, headers: {…}, transformRequest: Array(1), …}
data:
data:
url: "https://s3-ap-southeast-1.amazonaws.com/media.evaly.com.bd/media/images/d26acdb48506-ehealth.png"
url_sm: "https://df17fp68uwcso.cloudfront.net/eyJidWNrZXQiOiAibWVkaWEuZXZhbHkuY29tLmJkIiwgImtleSI6ICJtZWRpYS9pbWFnZXMvZDI2YWNkYjQ4NTA2LWVoZWFsdGgucG5nIiwgImVkaXRzIjogeyJyZXNpemUiOiB7IndpZHRoIjogMTUwLCAiaGVpZ2h0IjogMTUwLCAiZml0IjogImNvbnRhaW4ifSwgImJhY2tncm91bmQiOiB7InIiOiAyNTUsICJnIjogMjU1LCAiYiI6IDI1NSwgImFscGhhIjogMX0sICJmbGF0dGVuIjogdHJ1ZSwgImpwZWciOiB7InF1YWxpdHkiOiA3NX19fQ=="
__proto__: Object
message: "Image upload successful"
success: true
__proto__: Object
headers: {content-length: "551", content-type: "application/json"}
request: XMLHttpRequest {readyState: 4, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload, onreadystatechange: ƒ, …}
status: 201
statusText: "Created"
__proto__: Object
__proto__: Object

agreementInfos: Array(2)
0:
agreement_code: "ert8909"
agreement_expiry_date: "2021-06-05"
agreement_scan_copy: ""
credit_limit: 20
credit_time: 5
__proto__: Object
1:
agreement_code: "tyu3456"
agreement_expiry_date: "2021-06-05"
agreement_scan_copy: ""
credit_limit: 30
credit_time: 15
__proto__: Object
length: 2
__proto__: Array(0)
__proto__: Object

agreementCopy: ""

newCopy: undefined

how can I set the agreement_scan_copy image data in the agreementInfos Array?

uploadImageCore Component is here

export async function uploadImageCore(file: any) {
  const form = new FormData();
  form.append("image", file, file.name);
  try {
    const apiUrl = baseUrl.URL_CORE + "/image/upload";
    const res = await axios.post(apiUrl, form, {
      headers: {
        Authorization: "Bearer " + getTokenFromCookies(), //the token is a variable which holds the token
      },
    });

    if (equals(res.status, 201)) {
      return Promise.resolve(res);
    } else {
      return Promise.reject();
    }
  } catch (error) {
    // console.log(error);

    return Promise.reject(error.response.data);
  }
}

Upvotes: 0

Views: 64

Answers (1)

j.oli
j.oli

Reputation: 36

Why do you need a state here? Can't you just do agreementInfos[index].agreement_scan_copy = res.data.data.url;?

Upvotes: 1

Related Questions