在react js中,只发送formik表单submit中的非空值



我有一个react组件,我使用formik 提交表单

import { Field, Form, FormikProps, Formik } from "formik";
import {
Combobox,
ComboboxInput,
ComboboxOptionText,
ComboboxPopover,
ComboboxOption,
ComboboxList,
} from "@reach/combobox";
import {
createShop,
getMerchants,
getActiveMerchants,
} from "../../../request/shop";
import { useState } from "react";
import { useQuery } from "react-query";
import "styled-components/macro";
import Loader from "react-spinners/BarLoader";
import { useDebounce } from "use-debounce";
import { toast } from "react-toastify";
import { UploadImage } from "../../../common/UploadImage";
import { removeaSinglItem } from "../../../utils/helper";
import { KeyPerson } from "../component/KeyPerson";
import { CategoryHead } from "../component/CategoryHead";
import { BDM } from "../component/BDM";
import { KAM } from "../component/KAM";
import { VM } from "../component/VM";
import ImageUploadCrop from "../../../common/ImageUploadCrop";
import MapViewWithSearch from "../../../common/MapViewWithSearch";
import { Button } from "../../../common/Button";
export function CreateShop(): JSX.Element {
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 [searchMotherShopSlug, setSearchMotherShopSlug] = useState<string>("");
const [selectedSlug, setSelectedSlug] = useState<{
slug: string;
}>({ slug: "" });
const [throttledSlug] = useDebounce(searchMotherShopSlug, 500);
const querySlug = useQuery(
["slug-search", throttledSlug],
() =>
getMerchants(
selectedMerchant.merchant_code,
`slug=${searchMotherShopSlug}&limit=10&page=1`
),
{
enabled: Boolean(throttledSlug),
}
);
const merchantDetails = querySlug?.data?.data?.data?.shops ?? [];
const merchants = queryMerchantSearch?.data?.data?.data?.merchants ?? [];
return (
<div className="min-h-screen py-5 p-4">
<h1 className="mb-5">Create Shop</h1>
<Formik
initialValues={{
name: "",

logo_image: "",
image: "",
longitude: "",
latitude: "",
contact_number: "",
mother_shop_slug: "",
shop_type: "regular",
bin_no: "",
trade_license_no: "",
key_personnel: [
{
name: "",
designation: "",
phone_no: "",
email: "",
},
],
category_head: [
{
username: "",
},
],

}}
onSubmit={async (values, actions) => {
try {
actions.setSubmitting(true);
const reqbody: any = {
name: values.name,

longitude: values.longitude,
latitude: values.latitude,
logo_image: values.logo_image,
image: values.image,
contact_number: values.contact_number,
mother_shop_slug: selectedSlug.slug,
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,

};
const res = await createShop(reqbody);
if (res.status == 201) {
toast.success(res.data.message);
actions.setSubmitting(false);
await removeaSinglItem("createShop");
window.location.reload();
} else {
toast.error(res.data.message);
}
} catch (err) {
console.log(err);
actions.setSubmitting(false);
toast.error("Failed to create Shop");
}
}}
validate={(values) => {
const errors: any = {};
if (!values.name) {
errors.name = "Name is Required";
}
if (!values.address) {
errors.address = "Address is Required";
}
if (!values.latitude) {
errors.latitude = "Latitude is Required";
}
if (!values.longitude) {
errors.longitude = "Longitude is Required";
}
return errors;
}}
>
{(props: FormikProps<any>) => {
return (
<Form>
<fieldset className="border mb-2 p-4">
<legend className="px-2 ml-2 font-semibold">Shop:</legend>
<div className="flex items-center">
<div className="mb-6">
<ImageUploadCrop
title="Upload Logo"
setFieldValue={(value: string) =>
props.setFieldValue("logo_image", value)
}
logo={props.values.logo_image}
/>
</div>
<div className="ml-6 mb-6">
<ImageUploadCrop
title="Upload Cover Image"
setFieldValue={(value: string) =>
props.setFieldValue("image", value)
}
logo={props.values.image}
/>
</div>
</div>
<div className="grid grid-cols-2 gap-4 w-full">
<div className="mb-6">
<label htmlFor={"name"}>{"Name*"}</label>
<Field
type="text"
name="name"
placeholder="Name"
id={"name"}
className={"form-input"}
/>
{props.errors.name && (
<p className="text-red-500">{props.errors.name}</p>
)}
</div>

</div>


<div className="grid grid-cols-2 gap-4 w-full">
<div className="mb-6">
<label htmlFor={"latitude"}>{"Latitude*"}</label>
<Field
type="number"
name="latitude"
id="latitude"
className={"form-input"}
/>
{props.errors.latitude && (
<p className="text-red-500">{props.errors.latitude}</p>
)}
</div>
<div className="mb-6">
<label htmlFor={"longitude"}>{"Longitude*"}</label>
<Field
type="number"
name="longitude"
id="longitude"
className={"form-input"}
/>
{props.errors.longitude && (
<p className="text-red-500">{props.errors.longitude}</p>
)}
</div>
</div>
<div className="mb-6">
<MapViewWithSearch
lat={
props.values.latitude ? props.values.latitude : 23.777176
}
address={props.values.address}
lng={
props.values.longitude
? props.values.longitude
: 90.399452
}
onChangeAddress={(lat, lng, address) => {
props.setFieldValue("address", address);
props.setFieldValue("latitude", lat);
props.setFieldValue("longitude", lng);
}}
/>
</div>
<div className="grid grid-cols-2 gap-4 w-full">
<div className="mb-6">
<label htmlFor={"contact_number"}>{"Contact Number"}</label>
<Field
type="number"
name="contact_number"
id="contact_number"
className={"form-input"}
/>
</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 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="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={!props.values.is_delivery_hero_allowed}
onChange={() => {
props.setFieldValue(
"is_delivery_hero_allowed",
false
);
}}
/>{" "}
<span className="ml-2">No</span>
</label>
<label>
<input
name="is_delivery_hero_allowed"
type="radio"
checked={props.values.is_delivery_hero_allowed}
onChange={() =>
props.setFieldValue(
"is_delivery_hero_allowed",
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={!props.values.is_cod_allowed}
onChange={() => {
props.setFieldValue("is_cod_allowed", false);
}}
/>{" "}
<span className="ml-2">No</span>
</label>
<label>
<input
name="is_cod_allowed"
type="radio"
checked={props.values.is_cod_allowed}
onChange={() =>
props.setFieldValue("is_cod_allowed", true)
}
/>{" "}
<span className="ml-2">Yes</span>
</label>
</div>
</div>
</div>
</fieldset>
<fieldset className="border mb-2 p-4">
<legend className="px-2 ml-2 font-semibold">
Mother Shop:
</legend>
<div className="mb-4" role="group">
<p className="block mb-2">Is Mother Shop</p>
<label className="mr-4">
<input
name="is_mother_shop"
type="radio"
checked={!props.values.is_mother_shop}
onChange={() => {
props.setFieldValue("is_mother_shop", false);
}}
/>{" "}
<span className="ml-2">No</span>
</label>
<label>
<input
name="is_mother_shop"
type="radio"
checked={props.values.is_mother_shop}
onChange={() =>
props.setFieldValue("is_mother_shop", true)
}
/>{" "}
<span className="ml-2">Yes</span>
</label>
</div>
{!props.values.is_mother_shop && (
<div>
<Combobox>
<label className="relative block mb-2">
<p>Mother Shop Slug</p>
<ComboboxInput
placeholder="Search Mother Shop Slug ..."
className="form-input"
onChange={(e: any) =>
setSearchMotherShopSlug(e.target.value)
}
/>
</label>
{Array.isArray(merchantDetails) && (
<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>
) : merchantDetails.length > 0 ? (
<ComboboxList className="bg-white shadow-md ">
{merchantDetails.map(
(motherSlug, idx: number) => {
return (
<div
key={idx}
className="p-2 hover:bg-gray-100"
>
<div className="flex items-center">
<ComboboxOption
value={motherSlug.slug}
className="w-full text-xs cursor-pointer"
onClick={() => {
setSelectedSlug({
slug: motherSlug.slug,
});
}}
>
<ComboboxOptionText /> -{" "}
<span className="capitalize font-semibold">
{motherSlug.slug}
</span>
</ComboboxOption>
</div>
</div>
);
}
)}
</ComboboxList>
) : (
<div className="flex items-center justify-center p-8">
{throttledSlug
? "No results found"
: "Type Mother Shop slug ..."}
</div>
)}
</ComboboxPopover>
)}
</Combobox>
</div>
)}
{props.values.is_mother_shop && (
<div className="mb-6">
<>
<div className="grid grid-cols-2 gap-4 w-full">
<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={() =>
props.setFieldValue("key_personnel", [
...props.values.key_personnel,
{
name: "",
designation: "",
phone_no: "",
email: "",
},
])
}
className="float-right ml-4 text-sm underline"
>
Add Key Personnel
</button>
</p>
{props.values.key_personnel.map(
(
kp: {
name: 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={props.setFieldValue}
kps={props.values.key_personnel}
index={index}
kp={kp}
/>
</div>
)
)}
</div>
<div className="block mb-6">
<p className="mb-2">
Category Head
<button
type="button"
onClick={() =>
props.setFieldValue("category_head", [
...props.values.category_head,
{
username: "",
},
])
}
className="float-right ml-4 text-sm underline"
>
Add Category Head
</button>
</p>
{props.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={props.setFieldValue}
chs={props.values.category_head}
index={index}
ch={ch}
/>
</div>
)
)}
</div>

</div>
</>
</div>
)}
</fieldset>
<Button black type="submit">
Submit
</Button>
</Form>
);
}}
</Formik>
</div>
);
}

在当前的实现中,无论表单是否为空,我都会提交表单的所有值,但现在我的新API要求我在表单提交期间只提交表单中的非空字段。我如何在这个代码实现中做到这一点,或者Formik是否提供了任何方法或方式来实现这一点。

function nonEmptyObject(obj: any) {
for (const propName in obj) {
if (
obj[propName] === null ||
obj[propName] === undefined ||
obj[propName] === ""
) {
delete obj[propName];
}
}
return obj;
}
if (values.key_personnel) {
reqbody.key_personnel = values.key_personnel;
}
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 = nonEmptyObject(reqbody);
const res = await createShop(finalPayload);
console.log({ finalPayload });
console.log({ res });

最新更新