问题
I am using Formik/Yup for a validation of a page, which calls a GraphQL mutation. My code works fully:
export default function RemoveUserPage() {
const [isSubmitted, setIsSubmitted] = useState(false);
const [isRemoved ,setIsRemoved] = useState(false);
const [errorMessage, setErrorMessage] = useState('');
const [removeUser] = useMutation(RemoveUserMutation);
function submitForm(email: string) {
setIsSubmitted(true);
removeUser({
variables: {
email: email,
},
}).then(({ data }: any) => {
setIsRemoved(true);
console.log('info: ', data.deleteUser);
})
.catch((error: { message: string; }) => {
setIsRemoved(false);
console.log("Error msg:" + error.message);
setErrorMessage(error.message)
})
}
return (
<div>
<PermanentDrawerLeft></PermanentDrawerLeft>
<Formik
initialValues={{ email: '' }}
onSubmit={(values, actions) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
actions.setSubmitting(false);
}, 1000);
}}
validationSchema={schema}
>
{props => {
const {
values: { email },
errors,
touched,
handleChange,
isValid,
setFieldTouched
} = props;
const change = (name: string, e: any) => {
e.persist();
handleChange(e);
setFieldTouched(name, true, false);
};
return (
<div className='main-content'>
<form style={{ width: '100%' }}
onSubmit={e => {e.preventDefault();submitForm(email)
}}>
<div>
<TextField
variant="outlined"
margin="normal"
id="email"
name="email"
helperText={touched.email ? errors.email : ""}
error={touched.email && Boolean(errors.email)}
label="Email"
value={email}
onChange={change.bind(null, "email")}
/>
<br></br>
<Button
type="submit"
disabled={!isValid || !email}
>
Remove User</Button>
</div>
</form>
<br></br>
{isSubmitted && StatusMessage(isRemoved, errorMessage)}
</div>
)
}}
</Formik>
</div>
);
}
However, now I want to use useFormik
hook instead of <Formik>
and I am unable to do so. I have seen the following example but I just can't figure out how exactly I could syntactically use it in my case since I am using material ui components instead of formic-specific inputs.
https://jaredpalmer.com/formik/docs/api/useFormik
Edit:
This compiles and all but there's no validation happening on the textfields. What am I missing?
export const schema = Yup.object({
email: Yup.string()
.email('Invalid Email')
.required('This Field is Required'),
});
export default function RemoveUserPage() {
const [isSubmitted, setIsSubmitted] = useState(false);
const [isRemoved, setIsRemoved] = useState(false);
const [errorMessage, setErrorMessage] = useState('');
const [removeUser] = useMutation<DeleteUserResponse>(REMOVE_USER);
let submitForm = (email: string) => {
setIsSubmitted(true);
removeUser({
variables: {
email: email,
},
})
.then(({ data }: ExecutionResult<DeleteUserResponse>) => {
if (data !== null && data !== undefined) {
setIsRemoved(true);
console.log('info: ', data.deleteUser);
}
})
.catch((error: { message: string }) => {
setIsRemoved(false);
console.log('Error msg:' + error.message);
setErrorMessage(error.message);
});
};
const formik = useFormik({
initialValues:{ email: '' },
onSubmit:(values, actions) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
actions.setSubmitting(false);
}, 1000);
},
validationSchema:{schema}
})
const handleChange = (e: ChangeEvent<HTMLInputElement>)=>{
const {name,value} = e.target;
formik.setFieldValue(name,value);
}
return (
<div>
<PermanentDrawerLeft></PermanentDrawerLeft>
<Wrapper>
<Form
onSubmit={e => {
e.preventDefault();
submitForm(formik.values.email);
}}>
<div>
<TextField
variant="outlined"
margin="normal"
id="email"
name="email"
helperText={formik.touched.email ? formik.errors.email : ''}
error={formik.touched.email && Boolean(formik.errors.email)}
label="Email"
value={formik.values.email}
//onChange={change.bind(null, 'email')}
onChange={handleChange}
/>
<br></br>
<CustomButton
disabled={!formik.values.email}
text={'Remove User'}
/>
</div>
</Form>
<br></br>
{isSubmitted && StatusMessage(isRemoved, errorMessage)}
</Wrapper>
</div>
);
}
It gave me this error:
TypeError: schema[sync ? 'validateSync' : 'validate'] is not a function. (In 'schema[sync ? 'validateSync' : 'validate'](validateData, {
abortEarly: false,
context: context
})', 'schema[sync ? 'validateSync' : 'validate']' is undefined)
Secondly, earlier on, I was using isValid
for the button but now it gives an error. Is there an alternative?
回答1:
Like Jow Hawkins has mentioned it will be quite overwhelming to learn about hooks, but I will provide you some changes and answer to help you start.
export default function RemoveUserPage() {
const [isSubmitted, setIsSubmitted] = useState(false);
const [isRemoved ,setIsRemoved] = useState(false);
const [errorMessage, setErrorMessage] = useState('');
const [removeUser] = useMutation(RemoveUserMutation);
function submitForm(email: string) {
setIsSubmitted(true);
removeUser({
variables: {
email: email,
},
}).then(({ data }: any) => {
setIsRemoved(true);
console.log('info: ', data.deleteUser);
})
.catch((error: { message: string; }) => {
setIsRemoved(false);
console.log("Error msg:" + error.message);
setErrorMessage(error.message)
})
}
const formik = useFormik({
initialValues:{ email: '' },
onSubmit:(values, actions) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
actions.setSubmitting(false);
}, 1000);
},
validationSchema:schema
})
// depend on the return value
const handleSubmit = (someReturnValue or event)=>{
// if the return event has name
// such as event.target.name then you got the name
// and try event.target.value
// then set field value
// eg: const value = event.current.value
formik.setFieldValue(name, value)
}
// dont forget to set onBlur as well
// this i will leave it to you
return (
<div>
<PermanentDrawerLeft></PermanentDrawerLeft>
<div className='main-content'>
<form style={{ width: '100%' }}
onSubmit={formik.handleSubmit}>
<div>
<TextField
variant="outlined"
margin="normal"
id="email"
name="email"
helperText={formik.touched.email ? formik.errors.email : ""}
error={formik.touched.email && Boolean(formik.errors.email)}
label="Email"
value={formik.values.email}
onChange={handleChange}
/>
<br></br>
<Button
type="submit"
disabled={!isValid || !email}
>
Remove User</Button>
</div>
</form>
<br></br>
{isSubmitted && StatusMessage(isRemoved, errorMessage)}
</div>
</div>
);
}
Edit:
Since you are using Material Ui textfield
add a handleChange
method
const handleChange = (event)=>{
// get name and value from event.target
// is the same as const name = event.target.name
const {name,value} = event.target
// make sure you have name prop in
// your textfield and it is same name as your initial state
formik.setFieldValue(name,value) // this call formik to set your value
}
then in your email component
onChange={handleChange}
来源:https://stackoverflow.com/questions/60894094/change-formik-to-useformik