将状态值传递给 props,然后将 props 从 reactjs 中的子组件传递给父组件

时间:2021-05-28 19:23:22

标签: javascript reactjs state react-props

我有一个反应组件

/* eslint-disable react/prop-types */
import { useQuery } from "react-query";
import { FormikProps, FormikValues, Field } from "formik";
import { createFormModel, IfieldObject } from "../create/formik/CreateModel";
import {
  Combobox,
  ComboboxInput,
  ComboboxOptionText,
  ComboboxPopover,
  ComboboxOption,
  ComboboxList,
} from "@reach/combobox";
import { getActiveMerchants } from "../../../../../request/shop";
import { useState } from "react";
import "styled-components/macro";
import Loader from "react-spinners/BarLoader";
import { useDebounce } from "use-debounce";
import ImageUploadCrop from "../../../../../common/ImageUploadCrop";
import MapViewWithSearch from "../../../../../common/MapViewWithSearch";

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 const arrowIcon = `data:image/svg+xml;utf8,<svg width='15' height='7' viewBox='0 0 15 7' fill='none' xmlns='http://www.w3.org/2000/svg'>
<path fill-rule='evenodd' clip-rule='evenodd' d='M7.59952 7C7.37152 7 7.14452 6.923 6.95952 6.768L0.959518 1.768C0.535518 1.415 0.477518 0.784 0.831518 0.36C1.18452 -0.0640001 1.81452 -0.121 2.23952 0.232L7.61052 4.708L12.9725 0.393C13.4025 0.047 14.0325 0.115 14.3785 0.545C14.7245 0.975 14.6565 1.604 14.2265 1.951L8.22652 6.779C8.04352 6.926 7.82152 7 7.59952 7Z' fill='gray'/>
</svg>`;

export function BasicInformation({
  formikBag,
}: {
  formikBag: FormikProps<FormikValues>;
}): JSX.Element {
  const {
    name,
    logo_image,
    image,
    address,
    latitude,
    longitude,
    contact_number,
  }: IfieldObject = createFormModel;

  const [searchMerchantText, setSearchMerchantText] = useState<string>("");
  const [selectedMerchant, setSelectedMerchant] = useState<{
    merchant_name: string;
    merchant_code: string;
  }>({ merchant_name: "", merchant_code: "" });
  const [throttledMerchantText] = useDebounce(searchMerchantText, 500);
  const queryMerchantSearch = useQuery(
    ["merchant-search", throttledMerchantText],
    () => getActiveMerchants(`name=${searchMerchantText}&limit=10&page=1`),
    {
      enabled: Boolean(throttledMerchantText),
    }
  );

  const merchants = queryMerchantSearch?.data?.data?.data?.merchants ?? [];

  console.log({ selectedMerchant });

  return (
    <div className="py-10 px-6">
      <form>
        <div className="flex items-center">
          <div className="mb-6">
            <ImageUploadCrop
              title={logo_image?.label}
              setFieldValue={(value: string) =>
                formikBag.setFieldValue("logo_image", value)
              }
              logo={formikBag.values.logo_image}
            />
            {formikBag.errors.logo_image && (
              <p className="text-red-500">{formikBag.errors.logo_image}</p>
            )}
          </div>

          <div className="ml-6 mb-6">
            <ImageUploadCrop
              title={image?.label}
              setFieldValue={(value: string) =>
                formikBag.setFieldValue("image", value)
              }
              logo={formikBag.values.image}
            />
            {formikBag.errors.image && (
              <p className="text-red-500">{formikBag.errors.image}</p>
            )}
          </div>
        </div>
        <div className="grid grid-cols-2 gap-4 w-full">
          <div className="mb-6">
            <label htmlFor={"name"}>{name?.label}</label>
            <Field
              type="text"
              name="name"
              placeholder="Name"
              id={"name"}
              className={"form-input"}
            />
            {formikBag.errors.name && (
              <p className="text-red-500">{formikBag.errors.name}</p>
            )}
          </div>

          <div className="mb-6">
            <div>
              <Combobox>
                <label className="relative block mb-2">
                  <p>Merchant Name*</p>
                  <ComboboxInput
                    placeholder="Search Merchant ..."
                    className="form-input"
                    name="merchant_code"
                    onChange={(e: any) => {
                      // formikBag.handleChange(e.target.value);
                      setSearchMerchantText(e.target.value);
                    }}
                  />
                  {/* {formikBag.errors.merchant_code &&
                              formikBag.touched.merchant_code && (
                                <p className="text-red-500">
                                  {formikBag.errors.merchant_code}
                                </p>
                              )} */}
                </label>

                {Array.isArray(merchants) && (
                  <ComboboxPopover
                    portal={false}
                    className="absolute bg-white border w-auto"
                    css={`
                      z-index: 2001;
                    `}
                  >
                    {queryMerchantSearch.isLoading ? (
                      <div className="flex items-center justify-center p-4">
                        <Loader />
                      </div>
                    ) : merchants.length > 0 ? (
                      <ComboboxList className="bg-white shadow-md ">
                        {merchants.map((merchant, idx: number) => {
                          return (
                            <div key={idx} className="p-2 hover:bg-gray-100">
                              <div className="flex items-center">
                                <ComboboxOption
                                  value={merchant.merchant_name}
                                  className="w-full text-xs cursor-pointer"
                                  onClick={() => {
                                    setSelectedMerchant({
                                      merchant_name: merchant.merchant_name,
                                      merchant_code: merchant.merchant_code,
                                    });
                                  }}
                                >
                                  <ComboboxOptionText /> -{" "}
                                  <span className="capitalize font-semibold">
                                    {merchant.merchant_type}
                                  </span>
                                </ComboboxOption>
                              </div>
                            </div>
                          );
                        })}
                      </ComboboxList>
                    ) : (
                      <div className="flex items-center justify-center p-8">
                        {throttledMerchantText
                          ? "No results found"
                          : "Type merchant code ..."}
                      </div>
                    )}
                  </ComboboxPopover>
                )}
              </Combobox>
            </div>
          </div>
        </div>

        <div className="mb-6">
          <label htmlFor="description">Description</label>
          <Field
            type="text"
            name="description"
            as={"textarea"}
            id={"description"}
            className={"form-input"}
          />
        </div>

        <div className="mb-6">
          <label htmlFor={"address"}>{address?.label}</label>
          <Field
            type="text"
            name="address"
            id="address"
            className={"form-input"}
          />
          {formikBag.errors.address && (
            <p className="text-red-500">{formikBag.errors.address}</p>
          )}
        </div>

        <div className="grid grid-cols-2 gap-4 w-full">
          <div className="mb-6">
            <label htmlFor={"latitude"}>{latitude?.label}</label>
            <Field
              type="number"
              name="latitude"
              id="latitude"
              className={"form-input"}
            />
            {formikBag.errors.latitude && (
              <p className="text-red-500">{formikBag.errors.latitude}</p>
            )}
          </div>

          <div className="mb-6">
            <label htmlFor={"longitude"}>{longitude?.label}</label>
            <Field
              type="number"
              name="longitude"
              id="longitude"
              className={"form-input"}
            />
            {formikBag.errors.longitude && (
              <p className="text-red-500">{formikBag.errors.longitude}</p>
            )}
          </div>
        </div>

        <div className="mb-6">
          <MapViewWithSearch
            lat={
              formikBag.values.latitude ? formikBag.values.latitude : 23.777176
            }
            address={formikBag.values.address}
            lng={
              formikBag.values.longitude
                ? formikBag.values.longitude
                : 90.399452
            }
            onChangeAddress={(lat, lng, address) => {
              formikBag.setFieldValue("address", address);
              formikBag.setFieldValue("latitude", lat);
              formikBag.setFieldValue("longitude", lng);
            }}
          />
        </div>

        <div className="grid grid-cols-2 gap-4 w-full">
          <div className="mb-6">
            <label htmlFor={"longitude"} className="block">
              {contact_number?.label}
            </label>
            <input
              name="contact_number"
              type="text"
              value={formikBag.values.contact_number}
              onChange={formikBag.handleChange}
              maxLength={11}
              className={inputClass}
              placeholder="01xxxxxx"
              pattern="[0-9]+"
            />
            {formikBag?.errors?.contact_number ? (
              <small className="text-red-600">
                {formikBag?.errors?.contact_number}
              </small>
            ) : null}
          </div>

          <div className="mb-6">
            <label htmlFor={"shop_type"}>{"Shop Type"}</label>
            <Field as="select" name="shop_type" className="form-select">
              <option value="regular">Regular</option>
              <option value="campaign">Campaign</option>
              <option value="express">Express</option>
            </Field>
          </div>
        </div>
        <div className="grid grid-cols-2 gap-4 w-full">
          <div className="mb-4" role="group">
            <p className="block mb-2">Is Delivery Hero Allowed</p>
            <label className="mr-4">
              <input
                name="is_delivery_hero_allowed"
                type="radio"
                checked={!formikBag.values.is_delivery_hero_allowed}
                onChange={() => {
                  formikBag.setFieldValue("is_delivery_hero_allowed", false);
                }}
                value="false"
              />{" "}
              <span className="ml-2">No</span>
            </label>
            <label>
              <input
                name="is_delivery_hero_allowed"
                type="radio"
                checked={formikBag.values.is_delivery_hero_allowed}
                onChange={() =>
                  formikBag.setFieldValue("is_delivery_hero_allowed", true)
                }
                value="true"
              />{" "}
              <span className="ml-2">Yes</span>
            </label>
          </div>
          <div className="mb-4" role="group">
            <p className="block mb-2">Is Cash On Delivery Allowed</p>
            <label className="mr-4">
              <input
                name="is_cod_allowed"
                type="radio"
                checked={!formikBag.values.is_cod_allowed}
                onChange={() => {
                  formikBag.setFieldValue("is_cod_allowed", false);
                }}
                value="false"
              />{" "}
              <span className="ml-2">No</span>
            </label>
            <label>
              <input
                name="is_cod_allowed"
                type="radio"
                checked={formikBag.values.is_cod_allowed}
                onChange={() => formikBag.setFieldValue("is_cod_allowed", true)}
                value="true"
              />{" "}
              <span className="ml-2">Yes</span>
            </label>
          </div>
        </div>
      </form>
    </div>
  );
}

现在我想把selectedMerchant的状态值作为这个组件的props传递给一个父组件,父组件就是

import "styled-components/macro";
import { BiLeftArrowAlt, BiRightArrowAlt } from "react-icons/bi";
import { Formik, Form } from "formik";
import { BasicInformation } from "./BasicInformation";
import AdditionalInformations from "./AdditionalInformations";
import validationSchema from "../create/formik/ValidationSchema";
import React from "react";
import { createShop } from "../../../../../request/shop";
import { removeaSinglItem } from "../../../../../utils/helper";
import { Persist } from "../../../../../common/PersistFormData";
import { toast } from "react-toastify";
import Loader from "../../../../../common/Loader";
import { useNavigate } from "react-router-dom";
import { ROUTES } from "../../../../core/route";

function _renderStepContent(step: number, formikBag: any) {
  switch (step) {
    case 0:
      return <BasicInformation formikBag={formikBag} />;
    case 1:
      return <AdditionalInformations formikBag={formikBag} />;
    default:
      return <div>Not Found</div>;
  }
}
export const CreateMotherShop = (): JSX.Element => {
  const navigate = useNavigate();
  const STEPS: string[] = ["Basic Information", "Additional Information"];

  const [activeStep, setActiveStep] = React.useState(0);
  const currentValidationSchema = validationSchema[activeStep];
  const isSubmitStep = activeStep === STEPS.length - 1;
  const filter = (data: any) => {
    if (Array.isArray(data)) {
      const temp = data.reduce((r, v) => {
        v = filter(v);
        if (v !== "") r.push(v);
        return r;
      }, []);
      return temp.length ? temp : "";
    }
    if (data && typeof data === "object") {
      const temp = Object.entries(data).reduce((r, [k, v]) => {
        v = filter(v);
        if (v !== "") r.push([k, v]);
        return r;
      }, [] as [string, unknown][]);
      return temp.length ? Object.fromEntries(temp) : "";
    }
    return data;
  };
  function _handleBack() {
    setActiveStep(activeStep - 1);
  }
  async function _submitForm(values: any, actions: any) {
    try {
      actions.setSubmitting(true);
      const reqbody: any = {
        name: values.name,
        merchant_code: values.merchant_code,
        description: values.description,
        address: values.address,
        longitude: values.longitude,
        latitude: values.latitude,
        logo_image: values.logo_image,
        image: values.image,
        contact_number: values.contact_number,
        shop_type: values.shop_type,
        bin_no: values.bin_no,
        trade_license_no: values.trade_license_no,
        key_personnel: values.key_personnel,
        category_head: values.category_head,
        bdm: values.bdm,
        kam: values.kam,
        vm: values.vm,
        organisation_type: values.organisation_type,
        acquisition_info: values.acquisition_info,
        agreement_info: values.agreement_info,
        bank_account_name: values.bank_account_name,
        bank_account_no: values.bank_account_no,
        bank_name: values.bank_name,
        bank_branch_name: values.bank_branch_name,
        bank_branch_routing_no: values.bank_branch_routing_no,
        sbu_unit: values.sbu_unit,
        is_mother_shop: true,
        is_delivery_hero_allowed: values.is_delivery_hero_allowed,
        is_cod_allowed: values.is_cod_allowed,
      };
      if (values.key_personnel) {
        reqbody.key_personnel = values.key_personnel;
      }
      if (values.acquisition_info) {
        reqbody.acquisition_info = values.acquisition_info;
      }
      if (values.agreement_info) {
        reqbody.agreement_info = values.agreement_info;
      }
      if (values.category_head) {
        reqbody.category_head = values.category_head;
      }
      if (values.bdm) {
        reqbody.bdm = values.bdm;
      }
      if (values.kam) {
        reqbody.bdm = values.kam;
      }
      if (values.vm) {
        reqbody.vm = values.vm;
      }

      const finalPayload = filter(reqbody);

      const res = await createShop(finalPayload);

      if (res.status == 201) {
        toast.success(res.data.message);
        actions.setSubmitting(false);
        await removeaSinglItem("createShop");
        navigate(ROUTES.shop.linkTo);
      } else {
        toast.error(res.response.data.message);
      }
    } catch (err) {
      console.log(err);
      actions.setSubmitting(false);
      setActiveStep(0);
      toast.error("Failed to create Mother Shop");
      window.location.reload();
    }
  }
  function _handleSubmit(values: any, actions: any) {
    if (isSubmitStep) {
      _submitForm(values, actions);
    } else {
      setActiveStep(activeStep + 1);
      actions.setTouched({});
      actions.setSubmitting(false);
    }
  }
  return (
    <>
      <div
        css={`
          height: 60px;
        `}
        className="bg-white shadow border-b-2"
      >
        <div className="flex items-center h-full pl-6 pr-4">
          <nav className={"h-full flex items-center flex-grow"}>
            <ul className="flex">
              <li>
                <a href="/" className="text-gray-700 hover:text-black">
                  Home
                </a>
              </li>
              <li className="px-2 text-gray-600">•</li>
              <li>
                <a
                  href="/dashboard/shop/motherShop?page=1"
                  className="text-gray-700 hover:text-black"
                >
                  Mother Shops
                </a>
              </li>
              <li className="px-2 text-gray-600">•</li>
              <li>
                <a
                  href="/dashboard/shop/motherShop/create"
                  className="font-medium hover:text-black"
                >
                  Create Mother Shop
                </a>
              </li>
            </ul>
          </nav>
        </div>
      </div>
      <div className="container mx-auto pt-6 px-4">
        <div
          className="mb-6"
          css={`
            width: 800px;
            display: block;
            margin: 0 auto;
            margin-bottom: 1rem;
          `}
        >
          <h1>Create Mother Shop / {STEPS[activeStep]}</h1>
        </div>
        <div
          className=""
          css={`
            min-height: calc(100vh - 300px);
          `}
        >
          <div
            className="bg-white rounded-lg p-4"
            css={`
              width: 800px;
              display: block;
              margin: 0 auto;
            `}
          >
            <Formik
              enableReinitialize
              initialValues={{
                name: "",
                merchant_code: "",
                description: "",
                address: "",
                logo_image: "",
                image: "",
                longitude: "",
                latitude: "",
                contact_number: "",
                shop_type: "regular",
                bin_no: "",
                trade_license_no: "",
                key_personnel: [
                  {
                    username: "",
                    designation: "",
                    phone_no: "",
                    email: "",
                  },
                ],
                category_head: [
                  {
                    username: "",
                  },
                ],
                bdm: [
                  {
                    username: "",
                  },
                ],
                kam: [
                  {
                    username: "",
                  },
                ],
                vm: [
                  {
                    username: "",
                  },
                ],
                acquisition_info: [
                  {
                    acquisition_code: "",
                    acquisition_by: "",
                    acquisition_phone_no: "",
                    acquisition_email: "",
                    acquisition_date: "",
                  },
                ],
                agreement_info: [
                  {
                    agreement_code: "",
                    agreement_scan_copy: "",
                    agreement_expiry_date: "",
                    credit_limit: "",
                    credit_time: "",
                  },
                ],
                organisation_type: "small",
                bank_account_name: "",
                bank_account_no: "",
                bank_name: "",
                bank_branch_name: "",
                bank_branch_routing_no: "",
                sbu_unit: "",
                is_mother_shop: true,
                is_delivery_hero_allowed: false,
                is_cod_allowed: false,
              }}
              validationSchema={currentValidationSchema}
              onSubmit={_handleSubmit}
            >
              {(formikBag) => {
                return (
                  <Form id="createComapny">
                    {_renderStepContent(activeStep, formikBag)}
                    {!formikBag.isSubmitting && (
                      <Persist name="createComapny" />
                    )}
                    <div className="flex justify-end">
                      {activeStep !== 0 && (
                        <button
                          onClick={_handleBack}
                          className="flex bg-white rounded px-4 py-2 text-black items-center border "
                        >
                          <BiLeftArrowAlt size={20} />
                          <span className="mr-1">Previous</span>{" "}
                        </button>
                      )}
                      <button
                        disabled={formikBag.isSubmitting}
                        className="ml-5 bg-black rounded px-4 py-2 text-white"
                      >
                        {formikBag.isSubmitting ? (
                          <div className="flex items-center justify-center">
                            <Loader small color={"white"} />
                          </div>
                        ) : isSubmitStep ? (
                          <span className="mr-1">Submit</span>
                        ) : (
                          <span className="flex">
                            <span className="mr-1 items-center">Next</span>{" "}
                            <BiRightArrowAlt size={20} />
                          </span>
                        )}
                      </button>
                    </div>
                  </Form>
                );
              }}
            </Formik>
          </div>
        </div>
      </div>
    </>
  );
};

所以我想在行 selectedMerchant 中传递 <BasicInformation formikBag={formikBag} /> 道具,如 <BasicInformation formikBag={formikBag} selectedMerchant={selectedMerchant} /> 我试图在道具中添加状态,如

export function BasicInformation({
  formikBag,
  selectedMerchant,
}: {
  formikBag: FormikProps<FormikValues>;
  selectedMerchant: any;
}): JSX.Element {
-------- 
}

并传递像 <BasicInformation formikBag={formikBag} selectedMerchant={selectedMerchant} /> 这样的道具,但它给了我错误。

注意:我将无法在这个项目中使用任何类型的状态管理工具,如 Redux。

0 个答案:

没有答案