Formik component not being rendered with react-tabs - reactjs

I'm trying to use react-tabs with Formik but everytime i put the <Formik> tag, nothing gets rendered. This is what i'm trying to do:
<div className={classes.root}>
<Typography className={classes.headerText}>Editar lojista</Typography>
<Tabs>
<TabList>
<Tab>Loja e responsável</Tab>
<Tab>Segurança</Tab>
</TabList>
<Formik
initialValues={this.getInitalValues()}
onSubmit={(values, { setSubmitting }) => {
setTimeout(() => {
// alert(JSON.stringify(values, null, 2));
setSubmitting(false);
console.log(values);
}, 400);
}}
validationSchema={schema}>
{({
values,
errors,
touched,
handleChange,
handleBlur,
handleSubmit,
isSubmitting
/* and other goodies */
}) => (
<form className={classes.form}>
<TabPanel>
<MainLojistaForm /> {/* this is one component */}
</TabPanel>
<TabPanel>
<SegurancaForm /> {/* this is one component */}
</TabPanel>
<div className={classes.saveContainer}>
<Button
variant="contained"
type="submit"
className={classes.button}>
Salvar
</Button>
</div>
</form>
)}
</Formik>
</Tabs>
</div>
And this is a printscreen of what it looks like without Formik:
I really dont know what i'm doing wrong. Anyone ever had this issue?
The unique error i get is from react-tabs:
1.chunk.js:252727 Warning: Failed prop type: There should be an equal number of 'Tab' and 'TabPanel' in UncontrolledTabs. Received 2 'Tab'
and 0 'TabPanel'.

What you need to do is put Formik and form wrapping Tabs.

Related

Formik resetting form to initial values

I am using Formik and have the following setup below where I want to be able to reset the form when the user presses the "Cancel" button. On return to the form, all form values should be reset to initialValues which are all nulls.
<Formik
enableReinitialize
initialValues={{
...INITIAL_FORM_STATE
}}
validationSchema={ FORM_VALIDATION }
onSubmit={handleSubmit}
>
{({ values, errors, isSubmitting, isValid, setFieldValue, handleChange, resetForm }) => (
<Form>
.....
I have the following code for the Cancel button:
<Button
text="Cancel"
startIcon={<UndoIcon />}
variant="contained"
color="default"
className={classes.buttons}
component={Link}
to={'/home'}
onClick={() => {
{resetForm}
setMenu("Home")
}}
/>
After entering some text into a form field and pressing the Cancel button, which directs me back to the Home page, I then go back to the form and notice that my text is still in state within the form and not resetting.
Can anyone please assist with what I am missing.
<Button
text="Cancel"
startIcon={<UndoIcon />}
variant="contained"
color="default"
className={classes.buttons}
component={Link}
to={'/home'}
onClick={() => {
resetForm()
setMenu("Home")
}}
/>
You should use the resetForm() as a function call
you just need to set values of the input boxes to formik values:
<Formik
enableReinitialize
initialValues={{
...INITIAL_FORM_STATE
}}
validationSchema={ FORM_VALIDATION }
onSubmit={handleSubmit}
>
{({ values, errors, isSubmitting, isValid, setFieldValue, handleChange, resetForm }) => (
<input value={values.propertyName}/>
<Form>
and now resetForm should work well
You must change values through values since you dont have access to resetForm from the button.
<Button
text="Cancel"
startIcon={<UndoIcon />}
variant="contained"
color="default"
className={classes.buttons}
component={Link}
to={'/home'}
onClick={() => {
values = {
someProperty: null,
}
}}
/>
As as I see your are using Material UI. I notice that you have a "to" property in your Button component I think you have to decide either remaining on the same page and reset your form or redirecting to another page. If you want to remain on the same page I would suggest you to get rid of it because this causes some conflict. You can implement it like this:
return (<Formik
enableReinitialize
initialValues={{
...INITIAL_FORM_STATE
}}
validationSchema={ FORM_VALIDATION }
onSubmit={(values, actions) => {
actions.setSubmitting(false);
console.log("Submit form", values);
}}
>
{({ values, errors, isSubmitting, isValid, setFieldValue, handleChange, handleSubmit, resetForm }) => (
<Form onSubmit={handleSubmit}>
..... some inputs
<Button
text="Cancel"
startIcon={<UndoIcon />}
variant="contained"
color="default"
className={classes.buttons}
component={Link}
onClick={() => handleReset(resetForm)}
/>
</Form>
)}
</Formik>
);
And inside you class create a handleReset method:
const handleReset = (resetForm) => {
if (window.confirm('Reset?')) {
resetForm();
setMenu("Home");
}
};
`
const myForm = useFormik({
initialValues:{
value1:'',
value2:''
},
onSubmit:( values ) = >{
//submit data
........
//reset form after submit
myForm.resetForm()
}
)
on return
<form onSubmit={myForm.submit}>
........
<Button type="submit"/>
<Button onClick={()=>myForm.resetForm()}>Reset</Button>
</form>
`

How can I inject props to a child component without having to use the Consumer component?

How can I inject props from a Context consumer directly, without having to use the Consumer component? I would love to do it like the Formik example below but really not sure how I can achieve that. Any help is much appreciated.
// my example
<DropDown>
<DropDown.Toggle>
<button>Test</button>
</DropDown.Toggle>
<DropDownContext.Consumer>
{({ isOpen, toggle }) => (
<>
<DropDown.Contents>
<div className={isOpen ? "bg-green" : "bg-red"}></div>
</DropDown.Contents>
</>
)}
</DropDownContext.Consumer>
</DropDown>;
// what i want
<Formik
initialValues={{ name: "jared" }}
onSubmit={(values, actions) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
actions.setSubmitting(false);
}, 1000);
}}
>
{/* I don't want to have to use Context.Consumer */}
{(props) => (
<form onSubmit={props.handleSubmit}>
<input
type="text"
onChange={props.handleChange}
onBlur={props.handleBlur}
value={props.values.name}
name="name"
/>
{props.errors.name && <div id="feedback">{props.errors.name}</div>}
<button type="submit">Submit</button>
</form>
)}
</Formik>;

How can I make this Formik form work with custom Buttons I can't get the values to get to handleSubmit

I am learning React.js and I have this Codesandbox that is a a Material-Ui boilerplate. I try something now like I want the login Facebook Button when clicked to handle Facebook login.
I read the Docs and can't see any explanation for this situation. Even the Codesandbox Material-UI suggests this is a good approach.
This is what I have tried, it looks like this:
<Formik
initialValues={{
email: 'demo#devias.io',
password: 'Password123',
facebook: 'dddd',
}}
validationSchema={Yup.object().shape({
email: Yup.string().email('Must be a valid email').max(255).required('Email is required'),
password: Yup.string().max(255).required('Password is required'),
})}
onSubmit={(values, { setSubmitting }) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
setSubmitting(false);
}, 400);
}}
>
{({ errors, handleBlur, handleChange, handleSubmit, isSubmitting, touched, values }) => (
<form onSubmit={handleSubmit}>
<Box mb={3}>
<Typography color="textPrimary" variant="h2">
Sign in
</Typography>
<Typography color="textSecondary" gutterBottom variant="body2">
Sign in on the internal platform
</Typography>
</Box>
<Grid container spacing={3}>
<Grid item xs={12} md={6}>
<Button
className={classes.Facebook}
fullWidth
startIcon={<FacebookIcon />}
onClick={handleSubmit}
size="large"
variant="contained"
name="facebook"
type="facebook"
value={values.facebook}
>
SIGN in with Facebook
</Button>
</Grid>
........
As you see on the image the:
<Button
className={classes.Facebook}
fullWidth
startIcon={<FacebookIcon />}
onClick={handleSubmit}
size="large"
variant="contained"
name="facebook"
type="facebook"
value='sdsadadadsadada'
>
SIGN in with Facebook
</Button>
I have the type="facebook" and value='sdsadadadsadada set but when I click the button the onClick={handleSubmit} does not show this values in the handleSubmit , it show the default values like:
What I want is to handle login depending on this tree types, Facebook, Google or email. Do I have to create a Button onClick separately for the Facebook and Google Buttons to handle this? What am I doing wrong?
I found the answer here.
Basically it looks like this:
function FormContainer(props) {
const [formType, setFormType] = useState(DEFAULT_FORM_TYPE);
const handlerSubmit = (methodX, methodY) => async values => {
if (formType === FORM_TYPE_X) {
return await methodX(values);
}
return await methodY(values);
};
const submitFormType = (formTypeSubmited, handleSumitType) => () => {
setFormType(formTypeSubmited, () => handlerSubmit());
};
return (
<Formik
onSubmit={handlerSubmit(props.saveToApiMethodX, props.saveToApiMethodY)}
validate={values => props.validate(formType, values)}
>
{(values, handleSubmit, errors) => (
<>
<button onClick={submitFormType(FORM_TYPE_X, handlerSubmit)}>
Method X
</button>
<button onClick={submitFormType(FORM_TYPE_Y, handlerSubmit)}>
Method Y
</button>
</>
)}
</Formik>
);
}

Input loses focus when using custom input for Formik Field in FieldArray

I am using custom input components to handle my form data, and noticed strange behaviour. Only when I am using FieldArray with custom input components the input loses focus as I type.
Here is the form setup:
<Formik
enableReinitialize
initialValues={{ ...getInitialState() }}
onSubmit={(values, actions) => {
save(values, actions)
}}
validationSchema={schema}
>
{({ values, isSubmitting, setFieldValue, dirty }) => (
...
<Images />
...
)}
</Formik>
And inside my Images component
import { imageState } from "states"
import Input from "form/input"
function Images() {
...
return (
<div className={styles.wrapper}>
<FieldArray
name="images.posters"
render={({ form, push, remove }) => {
const images = form.values.images.poster
return (
<>
<button onClick={() => push(imageState)}>Add Poster</button>
{images.map((image, index) => (
<div key={index} className={styles.imageGroup}>
<Field //using custom input loses focus
name={`images.poster.${index}.src`}
component={Input}
/>
<Field //using Formik default component doesn't loose focus
name={`images.poster.${index}.src`}
/>
<button onClick={() => remove(index)}>Remove Poster</button>
</div>
))}
</>
)}}
/>
</div>
)
}
Is there another way I have to use custom inputs for FieldArray? I do not experience this problem when I am not using FieldArray.

How to reset / empty form after submit in Formik

So I've got my form. And I simply want it to be empty after the submit is successfull.
I've seen that I should be using enableReinitializing and change the value manually like : this.values.content = "".
But I'm not managing to understand where can I put this option?
<Formik
enableReinitializing //This is not working
initialValues={{
content: "",
}}
validationSchema={validAddMessageToProjectSchema(
this.props.intl.locale
)}
validateOnBlur={true}
onSubmit={ async ( values: AddMessageToProjectFormValue,
{ setSubmitting }: any
) => { await mutate({ variables: values });
setSubmitting(false);
}}
>
{({ isSubmitting, values, errors, touched, setFieldValue }) => {
return (
<Form className="addMessageToProject-form">
<div>
<FormattedMessage
id="addMessageToProject.descriptionField"
defaultMessage="Describe your post"
>
{msg => (
<Field
name="content"
placeholder={msg}
component={
TextAreaField
}
/>
)}
</FormattedMessage>
</div>
<Button
type="primary"
htmlType="submit"
className="addMessageToProject-form__submit form-submit"
disabled={isSubmitting}
>
<FormattedMessage
id="addMessageToProject.button"
defaultMessage="Send Message"
/>
</Button>
</Form>
);
}}
</Formik>
You can do it like this in onSubmit callback
onSubmit={(values, {setSubmitting, resetForm}) => {
handleSave(params, () => {
resetForm(initialValues)
})
setSubmitting(false);
}}
And this is not enableReinitializing instead use enableReinitialize

Resources