I will try to explain to the best where you can understand the issue.
If you see there is a button in both AddContact.js and EditContact.js, such as, Add button and Update button. They are wrapped by <Link to="/"></Link>. However, if I click on the button the event is not happening. If I comment the <Link> the event is being executed. I require both of my event handler and <Link> should work.
If you are going to comment or suggest me to put a event handler on button instead of onSubmit could you please explain why it is and why not it will work being the present way of code.
App.js
import React, { useState, useEffect } from "react";
import { BrowserRouter as Router, Route, Routes, useNavigate, useLocation } from 'react-router-dom';
import { v4 as uuid } from 'uuid';
import api from "../api/contacts";
import './App.css';
import Header from './Header';
import AddContact from './AddContact';
import EditContact from "./EditContact";
import ContactList from './ContactList';
import ContactDetail from './ContactDetail';
function App() {
const [contacts, setContacts] = useState([]);
const [searchTerm, setSearchTerm] = useState("");
const [searchResults, setSearchResults] = useState("");
const [editContactDetail, setEditContactDetail] = useState("");
//Retrieve Contacts
const retrieveContacts = async () => {
const response = await api.get("contacts");
return response.data;
};
const addContactHandler = async (singleContact) => {
const addContact = {
id: uuid(),
...singleContact
};
const addContactDone = await api.post("/contacts", addContact);
setContacts([...contacts, addContactDone.data]);
};
const removeContactHandler = async (id) => {
await api.delete(`/contacts/${id}`);
const newContactList = contacts.filter((deleteContact) => {
return deleteContact.id !== id;
});
setContacts(newContactList);
};
const searchHandler = (searchTerm) => {
setSearchTerm(searchTerm);
if (searchTerm !== "") {
const newContactList = contacts.filter((contact) => {
return Object.values(contact)
.join(" ")
.toLowerCase()
.includes(searchTerm.toLowerCase());
});
setSearchResults(newContactList);
} else {
setSearchResults(contacts);
}
};
const editChosenContact = (id) => {
const newContactList = contacts.filter((editRecord) => {
return editRecord.id === id;
});
setEditContactDetail(newContactList);
};
const updateContactPerson = async (selectedContactEdit) => {
const editResponse = await api.put(`/contacts/${selectedContactEdit.id}`, selectedContactEdit);
const {id, name, email} = editResponse.data;
setContacts( contacts.map(contact => {
return contact.id === id ? {...editResponse.data} : contact;
})
);
};
useEffect(() => {
const getAllContacts = async () => {
const allContacts = await retrieveContacts();
if(allContacts) setContacts(allContacts);
}
getAllContacts();
}, []);
useEffect(() => {
console.log("useEffect happening!");
}, [contacts]);
return (
<div>
<Router>
<Header/>
<Routes>
<Route exact path="/" element={ <ContactList contacts={ searchTerm.length < 1 ? contacts : searchResults } getContactId={ removeContactHandler }
getEditContact={editChosenContact} term={ searchTerm } searchKeyword={ searchHandler } /> }/>
<Route exact path="/add" element={ <AddContact addContactAction={ addContactHandler } /> }/>
<Route exact path="/edit/:id" element={ <EditContact editContactPerson={ editContactDetail } updateContactPerson={ updateContactPerson } /> }/>
<Route exact path="/contact/:id" element={ <ContactDetail /> }/>
</Routes>
</Router>
</div>
);
}
export default App;
AddContact.js
import React from "react";
import { Link } from "react-router-dom";
class AddContact extends React.Component {
state = {
name: "",
email: ""
}
add = (e) => {
e.preventDefault();
if (this.state.name === "" || this.state.email === "") {
alert("Enter name and email!");
return;
}
this.props.addContactAction(this.state);
this.setState({ name: "", email: ""});
};
render() {
return (
<div className="container">
<form onSubmit={ this.add }>
<div className="row">
<div className="col-sm-12 mt-5">
<h2>Add Contact</h2>
</div>
<div className="col-sm-6">
<label for="name">Name</label>
<input type="text" id="name" className="form-control" placeholder="name" aria-label="name" value={this.state.name} onChange={ (e) => this.setState({name: e.target.value}) }/>
</div>
<div className="col-sm-6">
<label for="email">Email</label>
<input type="text" id="email" className="form-control" placeholder="email" aria-label="email" value={this.state.email } onChange={ (e) => this.setState({email: e.target.value}) }/>
</div>
<div className="col-sm-12 mt-3">
<Link to="/">
<button className="btn btn-primary">Add</button>
</Link>
</div>
</div>
</form>
</div>
);
}
}
export default AddContact;
EditContact.js
import React from "react";
import { Link, useLocation } from 'react-router-dom';
import ContactCard from "./ContactCard";
import ContactDetail from "./ContactDetail";
class EditContact extends React.Component {
constructor(props){
super(props);
this.state = {
id: props.editContactPerson[0].id,
name: props.editContactPerson[0].name,
email: props.editContactPerson[0].email
};
}
update = (e) => {
e.preventDefault();
if(this.state.name !== "" && this.state.email !== "") {
this.props.updateContactPerson(this.state);
} else {
alert("All fields are mandatory!");
}
};
render() {
return (
<div className="container">
<form onSubmit={ this.update }>
<div className="row">
<div className="col-sm-12 mt-5">
<h2>Edit Contact</h2>
</div>
<div className="col-sm-6">
<label for="name">Name</label>
<input type="text" id="name" className="form-control" placeholder="name" aria-label="name" value={this.state.name} onChange={ (e) => this.setState({name: e.target.value}) }/>
</div>
<div className="col-sm-6">
<label for="email">Email</label>
<input type="text" id="email" className="form-control" placeholder="email" aria-label="email" value={this.state.email } onChange={ (e) => this.setState({email: e.target.value}) }/>
</div>
<div className="col-sm-12 mt-3">
<Link to="/">
<button className="btn btn-primary">Update</button>
</Link>
</div>
</div>
</form>
</div>
);
}
}
export default EditContact;
The issue as I see it is that the click event from the
buttonelement propagates up to theLinkcomponent and that navigation to"/"effectively kills anything the current page/component is processing. This means theformelement'sonSubmithandler isn't called.You've a couple options:
onClickevent handler to thebuttonand callstopPropagationon the click event object to prevent it from bubbling up to theLink.onClickevent handler to theLinkcomponent and callpreventDefaulton the click event object.In either case the goal here is to prevent the immediate navigation from occurring, so the
addandupdatehandlers will need to issue an imperative redirect.An example: