如何创建与 Formik 无缝协作的自定义选择组件?

问题描述 投票:0回答:2

我已经使用 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;
css reactjs typescript formik
2个回答
1
投票
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);
};

0
投票

你只需要使用

<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/>
组件,这给我带来了同样的问题。

您可以在 formik 文档 https://formik.org/docs/api/field

中阅读更多信息
© www.soinside.com 2019 - 2024. All rights reserved.