Let me tell you in brief what I am trying to do. As I am learning React, so following a tutorial and making a Contact Manager
, where it will take input of name and email address for now and will save it in local storage. When I will reload the page, it will retrieve data from local storage and display it. As I am in a learning phase, I am just exploring how the state works and how I can save data in local storage, Later I will save these data to a DB.
React version I am using is:
react: "18.1.0"
react-dom: "18.1.0"
and my node version is:
17.1.0
I am setting the form input data to local storage by doing this:
useEffect(() => {
localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(contacts));
}, [contacts]);
and retriving these data from local storage with the below code:
useEffect(() => {
const retriveContacts = JSON.parse(localStorage.getItem(LOCAL_STORAGE_KEY));
if (retriveContacts) {
setContacts(retriveContacts);
}
}, []);
I can see data is being stored in local storage from the Chrome Dev tool but whenever I am reloading the page, my goal is to retrieve the data from local storage and show the list. But after reloading, these data are not any longer visible on the page. I tried to debug, then I noticed, that when I am reloading the page, it's hitting the app.js
component twice, the first time it's getting the data, but the second time the data is being lost.
I got a solution here, where it's saying to remove the React.StrictMode
from index.js
and after doing so it's working fine.
Then I tried to replace the current index.js
with the previous react version (17.0.1) index.js
. This is the code I tried:
import React from "react";
import ReactDOM from "react-dom";
import App from "./components/App";
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById("root")
);
With this code, even with React.StrictMode
this seems to work fine, I mean my data does not clear from local storage after reloading.
My question is, what's the reason behind it? Am I missing something or there is some logic behind it? The solution link I have provided is 4 years ago, and React 18 was released some time ago, can't figure out what actually I am doing wrong!
Any help or suggestions will be appreciated.
Below are the components to regenerate the scenario.
Current index.js (version 18.1.0)
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./components/App";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
App.jsx
import React, { useState, useEffect } from "react";
import "../style/App.css";
import Header from "./Header";
import AddContact from "./AddContact";
import ContactList from "./ContactList";
function App() {
const LOCAL_STORAGE_KEY = "contacts";
const [contacts, setContacts] = useState([]);
const addContactHandler = (contact) => {
console.log(contact);
setContacts([...contacts, contact]);
};
useEffect(() => {
const retriveContacts = JSON.parse(localStorage.getItem(LOCAL_STORAGE_KEY));
if (retriveContacts) {
setContacts(retriveContacts);
console.log(retriveContacts);
}
}, []);
useEffect(() => {
localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(contacts));
}, [contacts]);
return (
<div className="ui container">
<Header />
<AddContact addContactHandler={addContactHandler} />
<ContactList contacts={contacts} />
</div>
);
}
export default App;
Header.jsx
import React from 'react';
const Header = () => {
return(
<div className='ui fixed menu'>
<div className='ui center container'>
<h2>
Contact Manager
</h2>
</div>
</div>
);
};
export default Header;
ContactList.jsx
import React from "react";
import ContactCard from "./ContactCard";
const ContactList = (props) => {
const listOfContact = props.contacts.map((contact) => {
return <ContactCard contact={contact}></ContactCard>;
});
return <div className="ui celled list">{listOfContact}</div>;
};
export default ContactList;
AddContact.jsx
import React from "react";
class AddContact extends React.Component {
state = {
name: "",
email: "",
};
add = (e) => {
e.preventDefault();
if (this.state.name === "" || this.state.email === "") {
alert("ALl the fields are mandatory!");
return;
}
this.props.addContactHandler(this.state);
this.setState({ name: "", email: "" });
};
render() {
return (
<div className="ui main">
<h2>Add Contact</h2>
<form className="ui form" onSubmit={this.add}>
<div className="field">
<label>Name</label>
<input
type="text"
name="name"
placeholder="Name"
value={this.state.name}
onChange={(e) => this.setState({ name: e.target.value })}
/>
</div>
<div className="field">
<label>Email</label>
<input
type="text"
name="email"
placeholder="Email"
value={this.state.email}
onChange={(e) => this.setState({ email: e.target.value })}
/>
</div>
<button className="ui button blue">Add</button>
</form>
</div>
);
}
}
export default AddContact;
ContactCard.jsx
import React from "react";
import user from '../images/user.png'
const ContactCard = (props) => {
const {id, name, email} = props.contact;
return(
<div className="item">
<img className="ui avatar image" src={user} alt="user" />
<div className="content">
<div className="header">{name}</div>
<div>{email}</div>
</div>
<i className="trash alternate outline icon"
style={{color:"red"}}></i>
</div>
);
};
export default ContactCard;
App.css
.main {
margin-top: 5em;
}
.center {
justify-content: center;
padding: 10px;
}
.ui.search input {
width: 100%;
border-radius: 0 !important;
}
.item {
padding: 15px 0px !important;
}
i.icon {
float: right;
font-size: 20px;
cursor: pointer;
}