I am trying to disable a button after it is clicked, but it is not holding its disabled tag. Another weird thing is that if I click the button twice it will disable. Code below
const [loading, setLoading] = useState('Submit');
...
<form onSubmit={(event) => {
event.preventDefault();
submitBet(units, line, team, gameID);
}}>
...
<button type='submit' className='submit-betslip' id='submit-button-id'>{loading}.</button>
</form>
The loading variable is a useState. The onSubmit function:
const submitBet = async (units, line, team, id) => {
if (Number(units) === 0 && Number(line) === 0) {
console.log('Empty input');
return
}
try {
document.getElementById('submit-button-id').disabled = true;
}
...
}
Not sure if it matters but the form is within a React function. Any thoughts?
Here is a simple example to what you want to do and it's working perfectly.
import React from "react";
import "./styles.css";
export default function App() {
const [loading, setLoading] = React.useState("Submit");
const handleSubmit = (e) => {
e.preventDefault();
setLoading("Submitting..");
setTimeout(() => {
alert("submitted Successfully");
setLoading("Submit");
}, 3000);
};
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<form onSubmit={handleSubmit}>
<input id="f1" name="f1" />
<button type="submit" disabled={loading !== "Submit"}>
{loading}.
</button>
</form>
</div>
);
}
Simply link the disable prop to the loading state.
If that is not what you want to do, just share the component with us, and I would love to help.
Related
I am porting a JS project to React, and got stuck on form submission (using various forms in the project to update profile description, name, upload pictures etc.). The simplest/shortest one simply confirms that you wish to delete a picture that you uploaded. The API part of the project is working fine (my GET, PATCH, DELETE requests are going through), but when I press any button with type=submit, the page reloads (even though preventDefault is set).
import PopupWithForm from './PopupWithForm';
function ConfirmDeletePopup(props) {
const isLoading = props.onLoading;
function handleSubmit(e) {
e.preventDefault();
props.onSubmit(props.card)
}
return (
<PopupWithForm name={'confirm-delete-form'} title='You sure?'
isOpen={props.isOpen}
onClose={props.onClose}
onSubmit={handleSubmit}
onLoading={props.onLoading}
card={props.card}>
<fieldset className={'popup__inputs'}>
<button type="submit"
className={`popup__submit-button popup__submit-button_type_confirm-delete-form
${isLoading && '.popup__submit-button_inactive'}
popup__form-submit-button_type_confirm-delete-form`}>
{isLoading? 'Deleting...' : 'Yes'}
</button>
</fieldset>
</PopupWithForm>
)
}
export default ConfirmDeletePopup
I tried running the pressing submit with react dev tools extension open, but it didn't help. I used react dev tools extensions to double check most of the state changes (like opening the popup, and toggling the 'loading' visual state on the button etc.), which were working as intended.
And code snipets relevant to this that I have within my App.js
const [isConfirmDeletePopupOpen, setConfirmDeletePopupState] = useState(false);
const [isConfirmDeleteLoading, setConfirmDeleteLoading] = useState(false);
const [deletedCard, setDeletedCard] = useState(null);
...
function handleCardDeleteSubmit(card) {
setConfirmDeleteLoading(true);
api.deleteCard(card._id)
.then(() => {
setCards((cards) => {
return cards.filter(c => {
return c._id !== card._id
});
});
closeAllPopups();
})
.catch(err => {
console.log(err);
})
.finally(() => {
setConfirmDeleteLoading(false);
})
}
...
function handleConfirmCardDelete(card) {
setConfirmDeletePopupState(true);
setDeletedCard(card);
}
...
<ConfirmDeletePopup isOpen={isConfirmDeletePopupOpen}
onClose={closeAllPopups}
onLoading={isConfirmDeleteLoading}
card={deletedCard}
onSubmit={handleCardDeleteSubmit}/>
And PopupWithForm (in case it helps to see things more clearly).
function PopupWithForm(props) {
return (
<div className={`popup popup_type_${props.name} ${props.isOpen? 'popup_opened':''}`}>
<div className="popup__container">
<button type="button"
onClick={props.onClose}
className={`popup__close-button popup__close-button_type_${props.name}`}
aria-label={`close${props.title}`}>{}</button>
<form className={`edit-form popup__form popup__form_type_${props.name}`}
name={props.name}
id={props.name}
noValidate>
<h2 className={`popup__heading ${props.name === 'update-avatar-form'?
'popup__form-heading_type_update-avatar-form': ''}`}>{props.title}</h2>
{props.children}
</form>
</div>
</div>
)
}
export default PopupWithForm;
Quentin was right, when I was refactoring my PopupWithForm I did not pass it the onSubmit hook, which is why the page was reloading on form submission.
The fixed version:
<form className={`edit-form popup__form popup__form_type_${props.name}`}
onSubmit={props.onSubmit}
name={props.name}
id={props.name}
noValidate>
<h2 className={`popup__heading ${props.name === 'update-avatar-form'?
'popup__form-heading_type_update-avatar-form': ''}`}>{props.title}</h2>
{props.children}
</form>
Do you tried to wrapping your component in a tag form?
const handleSubmit = (e) => {
e.preventDefault();
}
<form submit={handleSubmit}>
<button type="submit">Send</button>
</form>
I've been trying to debug this for hours and looked at every single other Stack Overflow question that has the same style of issue, but they all just say to use keys and that's still not working for me. I've made a simpler example of my code that replicates the error.
import React from 'react'
import { useState } from 'react'
const FormTest = () => {
const [name, setName] = useState('')
const TestExperience = (props) => {
return (<div>
<h1>Test Experience {props.num}</h1>
<input
type="text"
name="name"
placeholder="Name"
/>
</div>)
}
const processFormData = (event) => {
event.preventDefault();
console.log(event.target);
}
const [nums, setNums] = useState([1, 2, 3]);
const arr = nums.map((num, index) => <TestExperience num={num} key={index}/>);
return (
<div>
<form onSubmit={(event) => {
processFormData(event);
}}>
{arr}
<button onClick={() => {
setNums([...nums, nums.length + 1]);
}}>Add one!</button>
</form>
</div>
)
}
export default FormTest
I've tried moving TestExperience to it's own, separate function. I'm trying to basically have inputs that one can create more of, and this issue of losing focus came from the fact that every time an input was added, all of the existing formData disappeared due to a re-render. The goal would be to just use the onSubmit function to parse the data, but since it disappears after adding the input I figured I needed to store it. I've been going down rabbit hole after rabbit hole trying to fix what seems like such a simple problem and just keep running into issues with every implementation I try.
The overall goal is that I have a submit button and an add input button, and I tried to ditch the whole value={stateVariable} and onChange={setStateVariable} thing and just make the input button a "submit" button so that I can run the processFormData and do different things based on which submit button it was, but I have no clue how to check which button the submit came from when there's two different buttons, so an answer to that could be super helpful as well because then I can avoid this whole state mess.
You need to move the TestExperience out of FormTest.
import React from "react";
import { useState } from "react";
const TestExperience = (props) => {
const [name, setName] = useState("");
return (
<div>
<h1>Test Experience {props.num}</h1>
<input
type="text"
name="name"
placeholder="Name"
onChange={(event) => {
event.preventDefault();
setName(event.target.value);
}}
value={name}
/>
</div>
);
};
const FormTest = () => {
const processFormData = (event) => {
event.preventDefault();
console.log(event.target);
};
const [nums, setNums] = useState([1, 2, 3]);
const arr = nums.map((num, index) => (
<TestExperience num={num} key={index} />
));
return (
<div>
<form
onSubmit={(event) => {
processFormData(event);
}}
>
{arr}
//another way I tried to do it below //
{nums.map((num, index) => (
<TestExperience num={num} key={index} />
))}
<button
onClick={() => {
setNums([...nums, nums.length + 1]);
}}
>
Add one!
</button>
</form>
</div>
);
};
export default FormTest;
Code sandbox => https://codesandbox.io/s/trusting-elbakyan-mxrez?file=/src/App.js
Hi I have a Reactjs component in this component .I have a form inside the form i have a search field..when the user hit enter my component reloads.I want to use |prevent defaultso that mycomponentnot reloads when user hitsenter key.How to use in my code`
import React, { useState } from "react";
import data from "./info.json";
function App() {
const [searchTerm, setSearch] = useState(null);
return (
<div>
<form>
<input
type="text"
id=""
placeholder="Search"
onChange={(e) => setSearch(e.target.value)}
/>
</form>
{data
.filter((data) => {
if (searchTerm == null) {
return data;
} else if (
data.name.toLowerCase().includes(searchTerm.toLowerCase())
) {
return data;
}
})
.map((data) => (
<li>{data.name}</li>
))}
</div>
);
}
export default App;
ReactJS supports the onSubmit event by emitting synthetic events for native HTML elements.
For a <form> element, you can use the submit event to prevent the default behavior by using event.preventdefault().
You can do it in two easy steps:
Define an event handler for your form
Use the event handler to prevent form submission
import React, { useState } from "react";
import data from "./info.json";
function App() {
const [searchTerm, setSearch] = useState(null);
const fnHandleSubmit = event => {
event.preventDefault();
}
return (
<div>
<form onSubmit={fnHandleSubmit}>
<input
type="text"
id=""
placeholder="Search"
onChange={(e) => setSearch(e.target.value)}
/>
</form>
{data
.filter((data) => {
if (searchTerm == null) {
return data;
} else if (
data.name.toLowerCase().includes(searchTerm.toLowerCase())
) {
return data;
}
})
.map((data) => (
<li>{data.name}</li>
))}
</div>
);
}
export default App;
Add an onSubmit event handler on the form ,
<form onSubmit={handleOnsubmit}> </form>
in your handleOnsubmit function perfrom event.preventDefault()
function handleOnsubmit(event) {
event.preventDefault();
// Do Whatever you want
}
You will need to add preventDefault() to your form like so:
Add preventDefault() to your onSubmit event of your form:
<form onSubmit={e => e.preventDefault()}>
<input
type="text"
id=""
placeholder="Search"
onChange={e => {
setSearch(e.target.value);
}}
/>
</form>;
When clicked Enter, it triggers onSubmit(), default action is to refresh.
So to onSubmit() add preventDefault to overcome default behaviour.
Add the following line.
<form onSubmit={e => { e.preventDefault(); }}>
//code
</form>
The preventDefault() method cancels the event if it is cancelable, meaning that the default action that belongs to the event will not occur.
For example, this can be useful when:
Clicking on a "Submit" button, prevent it from submitting a form
Clicking on a link, prevent the link from following the URL
const Test = () => {
const submit = (e) => {
e.preventDefault();
console.log('I am here without refresh the form!')
}
return <form onSubmit={submit}>
<input type = 'text' ></input>
</form>
}
ReactDOM.render( <Test/> ,
document.getElementById("root")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id='root'></div>
All you need is to add e.preventDefault();
to your onSubmit function to prevent your component from reloading.
However, I'll advise you to use React UI solutions like Ant Design which provides the feature out of the box and also allow you to write your code more efficiently.
I have working code that helps me create a to-do list. Everything works almost well. When I click on the "Enter" key, my page reloads. Similarly, after reloading the page, all created elements disappear. I have 2 questions: can you show how to save all created elements after reloading and how to avoid reloading by pressing on "Enter"? Thank you very much
import React, {useState} from "react";
export function Creating_List () {
let [allTasks, setAllTasks] = useState([]);
let [input, setInput] = useState('');
let addTask = (myInput) => {
if (myInput){
let newTask = {
id: Math.random().toString(36).substr(2,9),
task: myInput,
complete: false
}
setAllTasks([...allTasks, newTask])
}
}
let taskDone = (id) => {
setAllTasks([allTasks.filter((todo => todo.id !== id))])
}
let handleInput = (e) => {
setInput(e.currentTarget.value)
}
let submitTask = (e) => {
e.preventDefault();
addTask(input);
setInput('');
}
return (<div className='tasks'>
<h1>Список задач {allTasks.length}</h1>
<form>
<input
type="text"
value={input}
onChange={handleInput}
placeholder="Нове завдання"
/>
</form>
<button onClick={submitTask} type="submit">Створити</button>
<div>
{allTasks.map(el => <div key={el.id}>{el.task} <button onClick={taskDone}>Виконано</button> </div>)}
</div>
</div>)
}
Change your <form> to <form onSubmit = {submitTask}>, this will prevent the page from reloading on enter since you have e.preventDefault(). If you want data to persist after reloading, you can use localStorage or a database like Firebase or MongoDB, or you can create your own backend using Node.js.
I have two buttons on a page and based on a state in that component, a particular button should be displayed, I have tried for hours, still not working
Here is my code
const App = () =>{
const [edit,setEdit] = useState(false)
const updateUser =() =>{
//update action
setEdit(false)
}
return(
<div>
<form>
<input type="text"/>
<input type="text"/>
{edit ? (<button onClick={()=>updateUser()}>Save</button>) : (<button onClick={()=>{setEdit(true)}}>Edit</button>)}
</form>
</div>
)
}
export default App;
when the page loads the button shows Edit, but after clicking, i expect it to change to save since edit is now true, but it still remains same
you have a side effect in this situation caused by edit so you should make use of good old pal useEffect also those prevenDefaults will prevent your form from refreshing and are necessary. I made a livedemo at codeSandbox and here is the code itself:
import React, { useState, useEffect } from "react";
const App = () => {
const [edit, setEdit] = useState(false);
const updateUser = (e) => {
e.preventDefault();
//update action
setEdit(false);
};
const editUser = (e) => {
e.preventDefault();
//stuffs you wanna do for editing
setEdit(true);
};
useEffect(() => {}, [edit]);
return (
<div>
<form onSubmit={(e) => updateUser(e)}>
<input type="text" />
<input type="text" />
{edit ? (
<button type="submit">Save</button>
) : (
<button onClick={(e) => editUser(e)}>Edit</button>
)}
</form>
</div>
);
};
export default App;
P.S: Although it works, I don't approve of the approach
You can try this approach also, Here I used e.preventDefault on the event when submitting the form to prevent a browser reload/refresh.
const App = () =>{
const [edit,setEdit] = useState(false)
const updateUser =(e) =>{
//update action
e.preventDefault();
setEdit(!edit);
}
return(
<div>
<form>
<input type="text"/>
<input type="text"/>
{edit ? (<button onClick={updateUser}>Save</button>) :
(<button onClick={updateUser}>Edit</button>)}
</form>
</div>
)
}
export default App;
Not need to using useEffect just check if edit is true or not !
EDIT : I made it this way so u can see what happend and i think u should learn more about react and hooks , i prefer watching youtube!
const App = () => {
const [edit, setEdit] = React.useState(true);
const clickHandler =(e)=>{
e.preventDefault();
if(!edit){
// update user information here not need to make
// different function and state or somthing else.
console.log("updateUser")
}
setEdit(prev=>!prev);
}
return(
<div>
<form>
<input type="text"/>
<input type="text"/>
<button onClick={clickHandler} disabled={!edit}>Edit</button>
<button onClick={clickHandler} disabled={edit}>Save</button>
</form>
</div>
)
}
ReactDOM.render(<App />, document.getElementById("react"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>
Issue
As I see it, your issue is that the buttons don't have a type specified to them, so they actually inherit an initial value of type="submit" and this causes your form to take the default submit action and reload the page. You likely aren't seeing this reload as it may be occurring very quickly.
type
The default behavior of the button. Possible values are:
submit: The button submits the form data to the server. This is the default if the attribute is not specified for buttons associated
with a <form>, or if the attribute is an empty or invalid value.
reset: The button resets all the controls to their initial values, like <input type="reset">. (This behavior tends to annoy users.)
button: The button has no default behavior, and does nothing when pressed by default. It can have client-side scripts listen to the
element's events, which are triggered when the events occur.
Solution
Provide/specify the button types to not be "submit and valid, i.e. use type="button".
const App = () => {
const [edit, setEdit] = React.useState(false);
const updateUser = () => {
//update action
setEdit(false);
};
return (
<div>
<form>
<input type="text" />
<input type="text" />
{edit ? (
<button type="button" onClick={updateUser}>
Save
</button>
) : (
<button
type="button"
onClick={() => {
setEdit(true);
}}
>
Edit
</button>
)}
</form>
</div>
);
};
Here is an example that also, IMO, make the code a bit more DRY.
const App = () => {
const [edit, setEdit] = React.useState(false);
const updateUser = () => {
//update action
setEdit(false);
};
return (
<div>
<form>
<input type="text" />
<input type="text" />
<button
type="button"
onClick={() => {
edit ? updateUser() : setEdit(true);
}}
>
{edit ? "Save" : "Edit"}
</button>
</form>
</div>
);
};
Demo