I’m working on react-phonebook app. I’m unable to understand the correct logic to edit the contact details.
On clicking the edit
button, I need to show the form and put name and number of that particular contact in the input fields and then take user input as the edited contact and display it in the list.
I’m facing the following issues:
If showForm
is false, it gives the error
Cannot set properties of null (setting 'value')
although I’ve added setShowForm(true)
in handleEdit
function but it still shows error but works when the form is already showing.
Here is the code:
import React, { useState } from "react";
const App = () => {
let phoneBookData = [{ name: "John Doe", number: 12345678 }];
const [contacts, setContacts] = useState(phoneBookData);
const [showForm, setShowForm] = useState(false);
const [userName, setUserName] = useState("");
const [number, setNumber] = useState("");
const handleDelete = (index) => {
console.log("index:", index);
let selectedIndex = index;
let newContacts = contacts.filter(
(_contact, index) => index !== selectedIndex
);
setContacts(newContacts);
};
const handleAddContact = () => {
if (userName.length === 0) {
alert("Please enter a valid name.");
return;
} else if (userName.includes("1")) {
alert("Name cannot contain any number or special character.");
return;
} else if (number.length === 0) {
alert("Please enter a valid number.");
return;
}
let newContact = { name: userName, number: number };
setContacts([...contacts, newContact]);
setUserName("");
setNumber("");
};
const handleEdit = (index) => {
setShowForm(true);
document.getElementById("number").value = number;
document.getElementById("name").focus();
document.getElementById("name").value = userName;
};
return (
<div id="main">
<div className="container-fluid">
<div className="row">
<div className="col-md-4"></div>
<div className="col-md-4">
<div className="App">
<h2 className="header">PhoneBook App</h2>
<span
style={{
cursor: "pointer",
color: "blue",
textDecoration: "underline",
}}
onClick={() => setShowForm(!showForm)}
>
{showForm ? "Hide Contact Form" : "Create New Contact"}
</span>
{showForm && (
<div className="container">
<form className="form">
<div className="form-group">
<input
type="text"
className="form-control"
placeholder="Name"
value={userName}
onChange={(e) => setUserName(e.target.value)}
id="name"
/>
</div>
<div className="form-group">
<input
type="text"
className="form-control"
placeholder="Number"
value={number}
onChange={(e) => setNumber(e.target.value)}
id="number"
/>
</div>
<button
type="button"
className="btn btn-primary icon-holder"
onClick={handleAddContact}
>
Add
</button>
</form>
</div>
)}
<p>There are {contacts.length} contacts saved in this book.</p>
{contacts.map((contact, index) => (
<div key={index} className="contacts">
<div className="contact-details">
<h5>
{index + 1}) {contact.name}
</h5>
<p>{contact.number}</p>
</div>
<button
className="icon-holder"
onClick={() => handleEdit(index)}
>
Edit
</button>
<button
className="icon-holder"
onClick={() => {
handleDelete(index);
}}
>
Delete
</button>
<hr />
</div>
))}
</div>
</div>
<div className="col-md-4"></div>
</div>
</div>
</div>
);
};
export default App;
Here is the link to codesandbox: https://codesandbox.io/p/sandbox/todos-app-listed-rxsd3p?file=%2Fsrc%2FApp.js%3A6%2C51
4
Answers
Don’t use DOM selectors like
document.getElementById
.In your case, the selectors return
null
because the corresponding elements are not yet on the page when you try to select them.Solution: get rid of the three
document.getElementById
calls, and add theautoFocus
prop to the field you want to focus.If you need a reference to an actual DOM element, read into
useRef
.you can manage the form state using React state management and check that the form input are controlled component. When clicking the edit button, populate the form field with the details of the selected contact. Upon updating the contact details, handle the state updates appropriately to reflect the changes in the contact list.
I hope it help.
This is where you are getting the error:
You are trying to get form elements of the form that you are not yet showing (async function call most probably) and you consequently get a
null
and you therefore cannot set thevalue
ofnull
.Try something like this:
and add
autoFocus
to the item you want.You can add useEffect for handling document updating if you want to access DOM elements directly
you can also add refs for better access to DOM elements
this will help you to change the values of inputs automatically every time the showForm state is changed and also ensure the DOM has updated before accesing DOM elements
or you can use controlled inputs instead to avoid this kind of bugs