我已经使用 TypeScript 和 Tailwind CSS 在 React 中创建了一个自定义的“Select”组件,但我在将其与 Formik 库集成以进行表单验证时遇到了问题。尽管我做出了努力,所选选项并未更新。我该如何排查并解决这个问题?
"use client"
import {FC, useState} from 'react';
interface SelectOption {
value: string;
label: string;
}
interface SelectProps {
label: string;
options: SelectOption[];
value?: string;
onChange: (value: string) => void;
className?: string;
}
const Select: FC<SelectProps> = ({ label, options, value, onChange, className }) => {
const [isOpen, setIsOpen] = useState(false);
const handleOptionClick = (optionValue: string) => {
setIsOpen(false);
onChange(optionValue);
};
const selectedOption = options.find((option) => option.value === value);
return (
<div className={"relative text-left cursor-pointer " + className}>
<label
className={`${
selectedOption?.value ? 'text-sm left-4 -top-3 px-1 bg-white z-10' : 'text-base top-2/4 transform -translate-y-2/4'
}
${isOpen ? 'text-cyan-500' : ''}
left-4 absolute pointer-events-none transition-all duration-200`}
htmlFor="select"
>
{label}
</label>
<div className="relative">
<div
className={`border-2 rounded-lg w-full h-14 px-4 py-4 focus:border-red-400 ${
isOpen ? 'border-cyan-500' : ''
}`}
onClick={() => setIsOpen(!isOpen)}
>
{selectedOption?.label}
</div>
{isOpen && (
<div className="absolute top-full left-0 right-0 border rounded-md bg-white shadow-lg select-none z-10">
{options.map((option) => (
<div
key={option.value}
className={`p-2 cursor-pointer hover:bg-gray-100`}
onClick={() => handleOptionClick(option.value)}
>
{option.label}
</div>
))}
</div>
)}
</div>
</div>
);
};
export default Select;
注册表单中还有一些字段,但为了方便我已将其删除。
"use client"
import {Button, FloatingInput, ProgressBar, Radio, Select} from "../../ui";
import {useState} from "react";
import {useFormik} from "formik";
import * as Yup from "yup";
const SignUpForm = () => {
const countryOptions = [
{
value: "US",
label: "United States"
}, {
value: "CA",
label: "Canada"
}, {
value: "FR",
label: "France"
}, {
value: "DE",
label: "Germany"
}
]
const formikAddress = useFormik({
initialValues: {
country: 'US',
},
validationSchema: Yup.object({
country: Yup
.mixed()
.oneOf(['US', 'CA', 'FR', 'DE'])
.required('Country is required'),
}),
onSubmit: async (values) => {
console.log(values)
}
});
return (
<>
<form onSubmit={formikAddress.handleSubmit} className={"space-y-6"}>
<Select
label="Country: *"
options={countryOptions}
value={formikAddress.values.country}
onChange={formikAddress.handleChange}
/>
<Button type={"submit"} className={"w-full"}>Weiter</Button>
</form>
</>
);
};
export default SignUpForm;
const handleOptionClick = (optionValue: string) => {
setIsOpen(false);
onChange(optionValue);
};
问题是您将一个字符串值传递给
handleChange
,它接受 ChangeEvent
。
解决方案可能是将
value
和 handleChange
绑定到隐藏输入,并通过输入的 onChange
事件处理程序中的内部状态处理显示的值
编辑:
否则你可以通过
setFieldValue
而不是 handleChange
const handleOptionClick = (optionValue: string) => {
setIsOpen(false);
// get fieldName from props
setFieldValue(fieldName, optionValue);
};
你只需要使用
<Field/>
formik 组件即可:
<Formik initialValues={{option: ""}}>
{({ error, touched }) => (
<Form>
<Field name="option" >
{({ field }) => (
<Select
{ ...field }
color={error.option && touched.option ? "failure" : ""}
>
<option value={"option 1"}>Option 1</option>
<option value={"option 2"}>Option 2</option>
</Select>
)}
</Field>
</Form>
)}
</Formik>
我和你有同样的问题,我使用的是 flowbite
<Select/>
组件,这给我带来了同样的问题。