9
votes

Validation à l'aide de Formik avec Yup et React-select

Je travaille avec une validation de formulaire de réaction en utilisant Yup avec Formik . Il y a un élément react-select dans le formulaire qui doit également être validé. Pour la validation, j'utilise validationSchema de Formik pour valider le formulaire lors du changement de valeur. Je n'ai besoin que de la valeur du champ de sélection sous forme de chaîne, donc je ne peux pas prendre l'objet complet (valeur-clé). Le champ de sélection fonctionne correctement même si le message d'erreur de validation n'est pas effacé. La question est de savoir comment puis-je valider le champ de sélection avec l'approche existante?

Voici l'exemple de code minimal.

import ReactDOM from "react-dom";
import React, { useState } from "react";
import { Grid, TextField, Button } from "@material-ui/core";
import { Formik } from "formik";
import * as Yup from "yup";
import Select from "react-select";
import "./styles.css";

function App() {
  const [selectedYear, setSelectedYear] = useState("");

  const testSchema = Yup.object().shape({
    name: Yup.string().required("Enter Name"),
    year: Yup.string().required("Select Year")
  });

  const initialValues = {
    name: "",
    year: ""
  };

  const handleYearChange = (selectedYear, values) => {
    values.year = selectedYear.value;
    console.log(selectedYear);
    setSelectedYear(selectedYear);
  };

  const yearOptions = [
    { value: "1960", label: "1960" },
    { value: "1961", label: "1961" },
    { value: "1962", label: "1962" },
    { value: "1963", label: "1963" },
    { value: "1964", label: "1964" },
    { value: "1965", label: "1965" }
  ];

  return (
    <Formik validationSchema={testSchema} initialValues={initialValues}>
      {({
        handleChange,
        handleBlur,
        values,
        errors,
        touched,
        handleSubmit,
        setFieldTouched
      }) => {
        return (
          <>
            <Grid container spacing={2}>
              <Grid item md={12} xs={12}>
                <TextField
                  label="Name"
                  name="name"
                  margin="normal"
                  variant="outlined"
                  onChange={handleChange("name")}
                  style={{ width: "100%", zIndex: 0 }}
                  value={values.name}
                  onBlur={() => {
                    console.log("name");
                  }}
                />
                {errors.name}
              </Grid>

              <Grid item md={6} xs={12}>
                <Select
                  placeholder="Year"
                  value={selectedYear}
                  onChange={selectedOption => {
                    handleYearChange(selectedOption);
                    // handleYearChange(selectedOption, values);
                    // values.year = selectedOption.value;
                    console.log("values", values.year);
                    handleChange("year");
                  }}
                  isSearchable={true}
                  options={yearOptions}
                  name="year"
                  isLoading={false}
                  loadingMessage={() => "Fetching year"}
                  noOptionsMessage={() => "Year appears here"}
                />
                {errors.year}
              </Grid>
              <Grid
                item
                md={4}
                style={{ marginTop: "24px", marginBottom: "10px" }}
                xs={12}
              >
                <Button onClick={handleSubmit}>Save</Button>
              </Grid>
            </Grid>
          </>
        );
      }}
    </Formik>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Voici les codesandbox:

Modifier throbbing-shadow-6f6yw

PS: Je suis nouveau sur Reactjs.


0 commentaires

3 Réponses :


11
votes

Changement

<pre>{JSON.stringify(props, null, 2)}</pre>

À

handleChange("year")(selectedOption.value);

Actuellement, le champ year dans la valeur Formik n'est pas mis à jour. La fonction handleChange () renvoie une nouvelle fonction qui peut être appelée avec une valeur pour mettre à jour l'état Formik.

Le moyen le plus simple de repérer ces choses consiste à générer les accessoires Formik avec le code suivant:

handleChange("year")

Voir ce bac à sable pour un exemple. Dans le bac à sable, j'ai complètement supprimé la nécessité de l'état d'année personnalisé. Je recommanderais d'utiliser uniquement l'état Formik pour manipuler les valeurs. En utilisant uniquement l'état Formik, vous n'aurez probablement à extraire que la partie année lors de l'enregistrement, car react-select utilise l'objet complet par défaut.


4 commentaires

Cela a fait l'affaire, cependant si j'utilise handleChange("year")(selectedOption.value); il n'affiche pas la valeur sélectionnée sur la boîte de react-select mais se reflète dans l'objet de values . Cependant, si je handleChange("year")(selectedOption); le handleChange("year")(selectedOption); puis il reflète l'option sélectionnée sur react-select et l'objet de valeurs semble avoir un objet imbriqué. Y a-t-il un moyen où l'objet de values n'a qu'une valeur de chaîne et non l'objet imbriqué?


Le package react-select requiert l'objet complet par défaut. L'auteur a écrit un package séparé pour permettre de ne transmettre que la partie valeur, vérifiez-le: github.com/jossmac/react-select-simple-value


@jagsler, merci beaucoup pour la dessiccation car cela m'a aidé à résoudre le même problème.


Je ne sais pas pourquoi mais cette méthode me lance une erreur disant Impossible de lire la propriété `` persist '' de undefined



2
votes

Au cas où quelqu'un chercherait des solutions à cela à l'avenir, voici une approche alternative pour obtenir la valeur sélectionnée sous forme de chaîne de react-select - et que Yup effectue toujours la validation sur l'entrée select:

En utilisant la fonction helpers de useField (), vous pouvez définir la valeur, le contact et l'état d'erreur d'un "Champ". useField () est utile chaque fois que vous travaillez avec des éléments qui ne sont pas des entrées, comme react-select.

function FormikSelect(...props) {
  const [field, meta, helpers] = useField(name="mySelectInput"); // can pass 'props' into useField also, if 'props' contains a name attribute
  const { setValue, setTouched, setError } = helpers;

  const setFieldProps = (selectedOption) => {
      setValue(selectedOption.value) 
      setTouched(true)
      setError(undefined)
  }

  return (
        <Select onChange={selectedOption => setFieldProps(selectedOption)} />
  );
};


0 commentaires

3
votes

solution facile :: ça marche pour moi ,, même pour tout autre type de champ d'entrée comme react-color ,, ou datepicker ... ,,, ici - handleChange vient de formik

<Select 
    className=" my-3 "
    name="year_value"
    id="year_value"
    placeholder='Choose Prevelage Level'
    value={values.year_value}
    onBlur={handleBlur}
    onChange={selectedOption => {
        let event = { target : { name:'year_value',value: selectedOption}}
        handleChange(event)
    }}
    onBlur={()=>{
      handleBlur({ target: {name:'year_value'} });
    }}
    options={yearOptions}
/>

})

validationSchema:yup.object({
 year_value :yup.string().required('*sales person is required.'),


0 commentaires