我有一个反应组件
/* 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。