使用 Formik 和 React 的可重用自定义输入组件的问题

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

在这里,我尝试创建一个自定义组件,它可以通过 props 接收数据并作为基本表单输入。

但是,我遇到了不显示错误的问题。有人可以解释一下我在实施中可能犯了什么错误吗?

如果有人有相关知识,我将非常感谢您帮助解决这个问题。

trying to build an reuseable component but now working why??

/* eslint-disable react/prop-types */



const Input = (props) => {
  const {formik, icon, title,type,otherState,btn1,btn2, name} = props
  Input.defaultProps = {
    type: "text",
    otherState: null,
    btn1: null,
    btn2: null,
    name: title.toLowerCase()
  }

   if (otherState) {
     var {state, setState} = otherState
   }
    if (btn1) {
      var {icon1, text1, action1} = btn1
    }
    if (btn2) {
      var {icon2, text2, action2} = btn2
    }

    


  return (
   <div className="mb-2">
   <span className="flex">
     <img className="w-6 h-6 mr-2" src={icon} alt={title} />
     <label
       htmlFor={name}
       className="block text-sm font-semibold text-textPrimary dark:text-dark_textPrimary"
     >
       {title}
     </label>
   </span>
   <span className="flex w-full">
{console.log(formik.touched.name)}
   <input
     
     type={type}
     name={name}
     value={formik.values.name}
     title={`${formik.touched.name && formik.values.name == "" ? `${title} is required` : ""}`}
     onChange={formik.handleChange}
     onBlur={formik.handleBlur}
     placeholder={
       formik.touched.name && formik.errors.name
         ? `${title} is required`
         : `${title}`
     }
     className={`block w-full px-4 py-2 mt-2 text-textPrimary dark:text-dark_textPrimary bg-background dark:bg-dark_background border-2 rounded-md focus:ring-secondary ${
       formik.touched.name && formik.errors.name 
         ? " border-error_red placeholder-error_red"
         : "border-cardBorder dark:border-dark_cardBorder"
     }`}
   />

     {
        btn1 || btn2 ? (
          <img
       className="w-6 h-7 cursor-pointer mt-3 transition duration-500 ease-in-out transform hover:-translate-y-1 hover:scale-110"
       onClick={() => action1()}
       src={state ? icon1 : icon2}
       title={!state ? text1 : text2}
     />) : null
     }
   </span>
{
     formik.touched.name && formik.errors.name && formik.values.name != "" ? (
       <h3 className="text-xs text-error_red">{formik.errors.name}</h3>
     ) : null
   }
 </div>
  )
}

export default Input


这是一个输入组件, 第一个组件用于电子邮件,第二个组件用于密码

<Input
          formik={formik}
          icon={emailIcon}
          title="Email"
          name="email"
          type="email"
          />

          <Input 
          formik={formik}
          icon={passwordIcon}
          name="password"
          title="Password"
          type={showPassword ? "password" : "text"}
          otherState={{'state':showPassword, 'setState':setShowPassword}}
          btn1={{'icon1':eyeOpenIcon, 'text1':"Hide Password", 'action1':() => setShowPassword(!showPassword)}}
          btn2={{'icon2':eyeCloseIcon, 'text2':"Show Password", 'action2':() => setShowPassword(!showPassword)}}
       

          />
javascript reactjs formik
2个回答
1
投票

要访问与给定输入相关的值或错误,您应该使用其名称。由于在您的

Input
组件中,您将名称作为
name
属性的一部分,因此您可以这样做:

formik.values[name]  // To access the value
formik.touched[name] // To check if it's checked
formik.errors[name]  // To gets its related error;

1
投票

Formik 有大量不同的示例,您可以在其 GitHub文档 上使用。

可以说,您可以构建他们的示例之一,而不是自行构建。

例如,有一个示例可以为字段验证提供即时反馈。看看这个 codesandbox 和下面的代码:

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import { useFormik, FormikProvider, Form, useField } from 'formik';
import './styles.css';
import * as Yup from 'yup';

const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

const TextInputLiveFeedback = ({ label, helpText, ...props }) => {
  const [field, meta] = useField(props);

  // Show inline feedback if EITHER
  // - the input is focused AND value is longer than 2 characters
  // - or, the has been visited (touched === true)
  const [didFocus, setDidFocus] = React.useState(false);
  const handleFocus = () => setDidFocus(true);
  const showFeedback =
    (!!didFocus && field.value.trim().length > 2) || meta.touched;

  return (
    <div
      className={`form-control ${
        showFeedback ? (meta.error ? 'invalid' : 'valid') : ''
      }`}
    >
      <div className="flex items-center space-between">
        <label htmlFor={props.id}>{label}</label>{' '}
        {showFeedback ? (
          <div
            id={`${props.id}-feedback`}
            aria-live="polite"
            className="feedback text-sm"
          >
            {meta.error ? meta.error : '✓'}
          </div>
        ) : null}
      </div>
      <input
        {...props}
        {...field}
        aria-describedby={`${props.id}-feedback ${props.id}-help`}
        onFocus={handleFocus}
      />
      <div className="text-xs" id={`${props.id}-help`} tabIndex="-1">
        {helpText}
      </div>
    </div>
  );
};

const Example = () => {
  const formik = useFormik({
    initialValues: {
      username: '',
    },
    onSubmit: async (values) => {
      await sleep(500);
      alert(JSON.stringify(values, null, 2));
    },
    validationSchema: Yup.object({
      username: Yup.string()
        .min(8, 'Must be at least 8 characters')
        .max(20, 'Must be less  than 20 characters')
        .required('Username is required')
        .matches(
          /^[a-zA-Z0-9]+$/,
          'Cannot contain special characters or spaces'
        ),
    }),
  });

  return (
    <FormikProvider value={formik}>
      <Form>
        <TextInputLiveFeedback
          label="Username"
          id="username"
          name="username"
          helpText="Must be 8-20 characters and cannot contain special characters."
          type="text"
        />
        <div>
          <button type="submit">Submit</button>
          <button type="reset">Reset</button>
        </div>
      </Form>
    </FormikProvider>
  );
};

ReactDOM.render(
  <div className="app">
    <h1 className="text-4xl">Accessible instant feeback with Formik 2</h1>
    <div className="example">
      <Example />
    </div>
   
  </div>,
  document.getElementById('root')
);
© www.soinside.com 2019 - 2024. All rights reserved.