When i am trying to add a new contact it is throwing Maximum call stack size exceeded
This is my App.js
import { useEffect, useState } from 'react';
import { AddContact } from './AddContact';
import { ContactList } from './ContactList';
import { Header } from './Header';
import { uuid } from 'uuidv4';
function App() {
const objKey ='contacts'
const [contacts,setContacts]=useState([]);
const detailsToParent = (contact) => {
const newContact = { id: uuid(), ...contact };
const updatedContacts = [...contacts, newContact];
setContacts(updatedContacts); // Update the state first
localStorage.setItem(objKey, JSON.stringify(updatedContacts));
};
useEffect(() => {
const localArray = JSON.parse(localStorage.getItem(objKey));
if (localArray) setContacts(localArray);
}, []);
const deleteContactHandler = (id) => {
const remainingContacts = contacts.filter((contact) => contact.id !== id);
setContacts(remainingContacts);
};
return ( <div>
<Header/>
<AddContact detailsToParent={detailsToParent}/>
<ContactList contacts={contacts} getContactId={deleteContactHandler} />
</div>)
}
export default App;
this is my contactList.js
import { Delete } from '@mui/icons-material';
import { Avatar } from '@mui/material';
import React from 'react';
export const ContactList = (props) => {
const list = props.contacts.map((contact) => {
return (
<div
className='d-flex shadow m-2 rounded p-4 bg-light justify-content-between align-items-end'
>
<div className='d-flex'>
<Avatar className='me-4' style={{ color: 'blue' }} />
<div>
<div>
<b>{contact.name}</b>
</div>
<div>{contact.email}</div>
</div>
</div>
<Delete
onClick={() => props.getContactId(contact.id) }
key={contact.id}
style={{ color: 'red' }}
/>
</div>
);
});
return (
<div>
<h5 className='ms-4 mt-4'>Contacts</h5>
{list}
</div>
);
};
This is my AddContact.js
import React from 'react'
export const AddContact = (props) => {
const details={
};
function add(e){
e.preventDefault();
var name = document.getElementById('name').value;
var email = document.getElementById('email').value;
details.name=name
details.email=email
document.getElementById('name').value=document.getElementById('name').defaultValue
document.getElementById('email').value=document.getElementById('email').defaultValue
if (details.name==='' || details.email===''){
alert('all the fields are mandatory!');
return
}
props.detailsToParent(details);
}
return (
<>
<div className='ps-3'>
<div className='mt-2 fs-2 fw-bold'>
Add Contact
</div>
<form onSubmit={(e) => add(e)}>
<div>
<label for='name' className='m-1 fw-bold'>Name </label><br/>
<input
type='text'
placeholder='name'
name='name'
id='name'
className='m-1 h-2 b-0 form-control'/>
</div>
<div>
<label for='email' className='m-1 fw-bold'>Email</label> <br/>
<input type='email' placeholder='[email protected]' name='email' className='m-1 b-0 form-control' id='email'/>
</div>
<input type='submit' value='add' className='btn btn-primary p-2 mt-2 px-5'/>
</form>
</div>
</>
)
}
I am expecting to add a new contact when i click on the add button. initially it worked well but i changed my code to delete the contact by clicking on the delete icon then it started to throw error.
2
Answers
Your
AddContact
component is missing a key concept of React: state. Try usingsetState
like:Runnable example:
In general, avoid
document.querySelector
. Avoiding direct DOM access is part of the point of React: you delcaratively design the UI and the React engine handles manipulating the DOM for you. Only bypass it rarely, with good reason, and generally use refs when you do.Same for reassignments–almost all component-oriented data goes through immutable state hooks. It’s good practice to treat non-state variables as immutable too.
By the way,
has a misleading comment. State updates are async and can only be read on the next render, so it’s good practice to move state setters to the end of functions so you’re not misled into thinking you can read the new value immediately. Luckily, in this case, you’re referring to
updatedContacts
, notcontacts
on thelocalStorage
line, so it’s good. But remove the comment and switch order to avoid confusion:The "Maximum call stack size exceeded" error from what i saw occurs because there is an issue with the way you are updating the state in your detailsToParent function. When you add a new contact, you are using the spread operator to create a new array called updatedContacts, but you are not correctly updating the state with this new array.
Here’s how you can fix the issue:
In the above code, you are using the previous state (contacts) to create a new array (updatedContacts). This is the correct way to update state in React when the new state depends on the previous state.
However, when you call setContacts(updatedContacts), React will re-render your component, and the useEffect hook will be triggered. In your useEffect hook, you are parsing the local storage and setting the state again, which causes an infinite loop, leading to the "Maximum call stack size exceeded" error.
To fix this issue, you can update your useEffect to only run once when the component mounts by passing an empty dependency array:
With this change, the useEffect will only run when the component first mounts, and subsequent updates to the contacts state won’t trigger it again.
I hope this is useful bro.