handleSubmit from formik is invoked whichever button I click - reactjs

I want to implement a checking form for validity into the project for ordering food using formik but I have encountered some problems creating two buttons. Whichever button is clicked the handleSubmit is invoked. what can I do to solve this problem?
Function goBack only sets the state to false.
export default function Checkout(props) {
function handleSubmit(event) {
// event.preventDefault();
console.log("Hello");
}
return (
<Formik
initialValues={{ userName: "Hi", street: "", postalCode: "", city: "" }}
onSubmit={handleSubmit}
>
{(props) => (
<Form className={styles["form"]}>
<div className={styles["form-control"]}>
<div className={styles["form-control__input"]}>
<label htmlFor="userName">Your name</label>
<Field type="text" name="userName" id="userName"></Field>
</div>
<div className={styles["form-control__input"]}>
<label htmlFor="street">Street</label>
<Field type="text" name="street" id="street"></Field>
</div>
<div className={styles["form-control__input"]}>
<label htmlFor="postalCode">Postal code</label>
<Field type="text" name="postalCode" id="postalCode"></Field>
</div>
<div className={styles["form-control__input"]}>
<label htmlFor="city">City</label>
<Field type="text" name="city" id="city"></Field>
</div>
</div>
<div className={styles["form-actions"]}>
<CloseButton type="button" onClick={props.goBack}>Back</CloseButton>
<OrderButton type="submit">Confirm</OrderButton>
</div>
</Form>
)}
</Formik>
);
}
export default function CloseButton(props) {
return <button type={props.type} onClick={props.onClick} className={styles["close-button"]}>{props.children}</button>;
}
export default function OrderButton(props) {
return <button type={props.type} onClick={props.onClick} className={styles['order-button']}>{props.children}</button>
}
I wanted CloseButton to close the form and go back to the list of orders, but it only invokes handleSubmit created by Formik component instead of the function in the props. I have read the documentation but there is neither anything about creating formik with two buttons nor anything related to my problem.

Looks like in props.goBack you meant to reference the props for the component, but instead the props from within Formik are being used (as that is the closest block declaration of props). Since goBack is not defined on the Formik props, you're passing undefined as the onClick handler to the button.
The most straightforward way to fix this is to rename one of the props variables—I'd suggest naming the Formik ones to formikProps or something similar.
A better approach, in my opinion, would be to destructure the props (in both cases, though only one is necessary), like this:
export default function Checkout({ goBack }) {
// ...
return (
<Formik>
{(props) => (
// ...
<CloseButton type="button" onClick={goBack}>Back</CloseButton>
// ...
)}
</Formik>
)
}

Related

Reactjs: How to clear text field after submission

I have a signup page which has 4 input text fields which changes the currentState of each field from an empty string to whatever I inputted. After signing up it logs each of the following 4 fields input in a database with a post request. How can I clear each field after clicking on the sign up button. Basically I just want the page to clear after clicking. I have attempted to set the state of the 4 variables back to an empty string at the end of my promise chain but nothing changes still.
import React,{useState} from 'react';
import style from './Signup.css';
import Axios from 'axios';
function Signup() {
const [firstReg, setFirstNameReg] = useState('')
const [lastReg, setLastNameReg] = useState('')
const [emailReg, setEmailReg] = useState('')
const [passReg, setPassReg] = useState('')
const register = () => {
Axios.post('http://localhost:3001/register', {
first_name: firstReg,
last_name: lastReg,
email: emailReg,
password: passReg,
}).then((response)=> {
console.log(response);
setFirstNameReg('')
});
};
return (
<div className="Signup">
<div className='Sign'>
<div class="photo"> Create an account</div>
<div class ='searche'>
<div className="searchInputse">
<input type="text" onChange={(e)=> {setFirstNameReg(e.target.value)}} placeholder={'First name'} />
<div className="searchIcone"></div>
</div>
<div className="dataResult"></div>
</div>
<div class ='searche'>
<div className="searchInputse">
<input type="text" onChange={(e)=> {setLastNameReg(e.target.value)}} placeholder={'Last name'}/>
<div className="searchIcone"></div>
</div>
<div className="dataResult"></div>
</div>
<div class ='searche'>
<div className="searchInputse">
<input type="text" onChange={(e)=> {setEmailReg(e.target.value)}} placeholder={'Email'}/>
<div className="searchIcone"></div>
</div>
<div className="dataResult"></div>
</div>
<div class ='searche'>
<div className="searchInputse">
<input type="text" onChange={(e)=> {setPassReg(e.target.value)}} placeholder={'Password'}/>
<div className="searchIcone"></div>
</div>
<div className="dataResult"></div>
</div>
<button className='searchee' onClick={register}>
Sign Up
</button>
</div>
</div>
);
}
export default Signup;
A few things you should be aware of.
1st. You want to keep your data in an object for easy management and code reduction like so:
Define the initial object outside of your component;
let initialValues = {
'first_name': '',
'last_name': '',
'email': '',
}
And inside your component define state with the initialValues variable as the state default.
const [data, setData] = useState(initialValues);
And then, in your JSX you can connect the values with the object keys like so:
<input type="text" name="first_name" value={data.first_name} />
<input type="text" name="last_name" value={data.last_name} />
<input type="text" name="email" value={data.email} />
You can also then add an onChange handler to that input like so:
note: name must match the key inside of the initalValues object.
<input type="text" name="first_name" value={data.first_name} onChange={handleChange} />
<input type="text" name="last_name" value={data.last_name} onChange={handleChange} />
<input type="text" name="email" value={data.email} onChange={handleChange} />
handleChange basic function can look like this:
const onChange = (e) => {
setData({...data, [e.target.name]: e.target.value})
}
Essentially all you're doing is typing inside the input field, onChange detects a change on each key press, and fires off the handleChange function, that function makes a copy of the current state of data then looks at the e.target.name which could be first_name and sets it to e.target.value which is anything you type.
That way, all you need to pass to axios is the data object.
I hope this helps, let me know if you have any other questions.
Happy coding!
Hi try to replace your register button with this :
<button className='searchee' onClick={()=>{register();setFirstNameReg('');setLastNameReg('');setEmailReg('');setPassReg('')}}>
Sign Up
</button>

In React with Formik how can I build a search bar that will detect input value to render the buttons?

New to Formik and React I've built a search component that I'm having issues with the passing of the input value and rendering the buttons based on input length.
Given the component:
const SearchForm = ({ index, store }) => {
const [input, setInput] = useState('')
const [disable, setDisable] = useState(true)
const [query, setQuery] = useState(null)
const results = useLunr(query, index, store)
const renderResult = results.length > 0 || query !== null ? true : false
useEffect(() => {
if (input.length >= 3) setDisable(false)
console.log('input detected', input)
}, [input])
const onReset = e => {
setInput('')
setDisable(true)
}
return (
<>
<Formik
initialValues={{ query: '' }}
onSubmit={(values, { setSubmitting }) => {
setInput('')
setDisable(true)
setQuery(values.query)
setSubmitting(false)
}}
>
<Form className="mb-5">
<div className="form-group has-feedback has-clear">
<Field
className="form-control"
name="query"
placeholder="Search . . . . ."
onChange={e => setInput(e.currentTarget.value)}
value={input}
/>
</div>
<div className="row">
<div className="col-12">
<div className="text-right">
<button type="submit" className="btn btn-primary mr-1" disabled={disable}>
Submit
</button>
<button
type="reset"
className="btn btn-primary"
value="Reset"
disabled={disable}
onClick={onReset}
>
<IoClose />
</button>
</div>
</div>
</div>
</Form>
</Formik>
{renderResult && <SearchResults query={query} posts={results} />}
</>
)
}
I've isolated where my issue is but having difficulty trying to resolve:
<Field
className="form-control"
name="query"
placeholder="Search . . . . ."
onChange={e => setInput(e.currentTarget.value)}
value={input}
/>
From within the Field's onChange and value are my problem. If I have everything as posted on submit the passed query doesn't exist. If I remove both and hard code a true for the submit button my query works.
Research
Custom change handlers with inputs inside Formik
Issue with values Formik
Why is OnChange not working when used in Formik?
In Formik how can I build a search bar that will detect input value to render the buttons?
You need to tap into the props that are available as part of the Formik component. Their docs show a simple example that is similar to what you'll need:
<Formik
initialValues={{ query: '' }}
onSubmit={(values, { setSubmitting }) => {
setInput('')
otherStuff()
}}
>
{formikProps => (
<Form className="mb-5">
<div className="form-group has-feedback has-clear">
<Field
name="query"
onChange={formikProps.handleChange}
value={formikProps.values.query}
/>
</div>
<button
type="submit"
disabled={!formikProps.values.query}
>
Submit
</button>
<button
type="reset"
disabled={!formikProps.values.query}
onClick={formikProps.resetForm}
>
</Form>
{/* ... more stuff ... */}
)}
</Formik>
You use this render props pattern to pull formiks props out (I usually call them formikProps, but you can call them anything you want), which then has access to everything you need. Rather than having your input, setInput, disable, and setDisable variables, you can just reference what is in your formikProps. For example, if you want to disable the submit button, you can just say disable={!formikProps.values.query}, meaning if the query value in the form is an empty string, you can't submit the form.
As far as onChange, as long as you give a field the correct name as it corresponds to the property in your initialValues object, formikProps.handleChange will know how to properly update that value for you. Use formikProps.values.whatever for the value of the field, an your component will read those updates automatically. The combo of name, value, and onChange, all handled through formikProps, makes form handing easy.
Formik has tons of very useful prebuilt functionality to handle this for you. I recommend hanging out on their docs site and you'll see how little of your own code you have to write to handle these common form behaviors.

React hook form Rendering too many times

I am trying to do something like this.
When user Click on Edit Button then Form fields will appear and user can edit the data. otherwise user can only view the data.
I facing the trouble, when user don't want to edit the form and click on cancel button then page start rendering as many times as the page have total form fields.
On my original form I have 80+ form fields and when user click on cancel button page becomes very slow.
When I remove
ref={register}
from my page then form don't render to many times, but form does not submit with the data.
Is there any way to stop extra rendering?
Here is my code and logic.
Thanks for your attention.
import React, { useState } from "react";
import { useForm } from "react-hook-form";
function Test() {
const { register, handleSubmit } = useForm();
const [edit, setEdit] = useState(false);
const onSubmit = (data) => {
console.log(data);
};
return (
<div className="App">
<header className="App-header">
{console.log("I am redering.")}
<form onSubmit={handleSubmit(onSubmit)}>
<a
href=""
onClick={(e) => {
setEdit(!edit);
e.preventDefault();
}}
>
{edit ? "Cancel" : "Edit"}
</a>
{edit && (
<p>
<input
type="text"
name="email"
ref={register}
placeholder="Email"
/>
</p>
)}
{edit && (
<p>
<input
type="text"
name="firstname"
ref={register}
placeholder="First Name"
/>
</p>
)}
{edit && (
<p>
<input
type="text"
name="lastname"
ref={register}
placeholder="Last Name"
/>
</p>
)}
{edit && (
<>
<input
type="checkbox"
name="contact[]"
id="contact-one"
value="1"
ref={register}
/>
<label htmlFor="contact-one">One</label>
</>
)}
{edit && (
<>
<input
type="checkbox"
name="contact[]"
id="contact-two"
value="2"
ref={register}
/>
<label htmlFor="contact-two">Two</label>
</>
)}
{edit && <button type="submit">Submit</button>}
{edit === false && (
<>
<p>{`My First Name`}</p>
<p>{`My Last Name`}</p>
<p>{`My Email address`}</p>
<p>{`My Contacts`}</p>
</>
)}
</form>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default Test;
<form onSubmit={handleSubmit(onSubmit)}>
This is a function call, which means this gets called immediatelt the form is created on the DOM, your event listeners need to take a reference to the function which will then get called when the event occurs, to do that you wrap this function call in another anonymous function. Then the function will get called when the submit event occurs. So you need to do this
<form onSubmit={()=>{handleSubmit(onSubmit)}}>
Also since this is a submit event, you might want to stop the default behaviour which refreshes the page. Like this
<form onSubmit={(ev)=>{
ev.preventDefault()
handleSubmit(onSubmit)}}>
Update
I did not look at the JSX properly. There are a few things you are probably doing wrong
using ref to get input values rather than state
when taking in any kind of input you want to convert those fields into control components Officila docs on controlled components
I suggest you understand this and state first, that will help you a lot. React docs still uses class components in example code but simply use use state instead of this.state for state varibales

Formik handleBlur use case

What are use cases for handleBlur? Since you can access touched fields through the touched object.
From Formik Docs:
handleBlur: (e: any) => void
onBlur event handler. Useful for when you need to track whether an input has been touched or not. This should be passed to <input onBlur={handleBlur} ... />
handleBlur is how touched is actually updated (or at least one of the ways). If your input isn't passed an onBlur handler connecting to Formik's state, the touched state won't be updated.
Here is a codesandbox illustrating the behavior: https://codesandbox.io/s/magical-gates-4cq5k?file=/src/App.js
If you blur the first input, touched is updated. If you blur the second input, touched is not updated. The third input uses useField, which results in an onBlur field being passed to my input automatically. This is typically how I like to work with Formik (or pretty much any other react form library), since it cuts down on the boilerplate necessary to connect form fields to the state of the form.
import React from "react";
import { Formik, Form, useField } from "formik";
import "./styles.css";
export default function App() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<Formik
initialValues={{ usingUseField: "", withBlur: "", withoutBlur: "" }}
>
{({ handleChange, handleBlur, values, touched }) => {
return (
<Form>
{JSON.stringify(touched)}
<div>
<label>
With Blur
<input
onBlur={handleBlur("withBlur")}
onChange={handleChange("withBlur")}
value={values.withBlur}
/>
</label>
</div>
<div>
<label>
Without Blur
<input
onChange={handleChange("withoutBlur")}
value={values.withoutBlur}
/>
</label>
</div>
<InputUsingUseField name="usingUseField" label="Using useField" />
</Form>
);
}}
</Formik>
</div>
);
}
function InputUsingUseField({ label, name }) {
const [props] = useField(name);
return (
<div>
<label>
{label}
<input {...props} />
</label>
</div>
);
}

Unable to change Formik forms text field

I am using the following code:
<Formik initialValues={{val:cell.value}}>
<Form>
<Field type="text" name="val" size="2" onChange = {(e)=> {console.log(e.target)}}></Field>
</Form>
</Formik>
and I am unable to change the value at UI. What am I doing wrong?
Formik should be handling the changes. See the following example: https://jaredpalmer.com/formik/docs/api/formik
Note that the input in the example is triggering Formik's handleChange in the onChange:
onChange={props.handleChange}
App.js
I used functional component and useState.
const App = () => {
const cell = { value: "test" };
const [myVal, setMyVal] = useState(cell.value);
return (
<div>
<Formik initialValues={{ val: cell.value }}>
<Form>
<Field
type="text"
name="val"
size="20"
placeholder="type something"
value={myVal}
onChange={e => {
console.log(e.target.value);
setMyVal(e.target.value);
}}
/>
</Form>
</Formik>
</div>
);
};
check out the demo code
In your onChange, you need to update the state, which then gets passed back into Formik. Right now you are just outputting the value.

Resources