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:
PS: Je suis nouveau sur Reactjs.
3 Réponses :
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.
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
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)} /> ); };
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.'),