user16511963
user16511963

Reputation:

Losing useState Value on Refresh in React.js

I am sending an id from ProductListing Component and I am receiving that id using useParams in ProductDetail Component. In ProductDetail Component I am finding an object using find method and then I am setting it into singleProduct state. On refresh I get singleProduct is undefined.

imports

import React, { useState, useEffect } from "react";
import { NavLink, useParams } from "react-router-dom";
import Loading from "../other/Loading";

state

const ProductDetail = () => {
  const [loading, setLoading] = useState(false);
  const [products, setProducts] = useState([]);
  const [singleProduct, setSingleProduct] = useState({});

receiving an id using useParams

  const { id } = useParams();

useEffect

  useEffect(() => {
   //GETTING PRODUCTS ARRAY
    getProductListingData();
   //FINDING A SINGLE OBJECT
    getProductID();
  }, []);

getting products array

const getProductListingData = async () => {
    try {
      const response = await fetch("http://localhost:8000/productListing");
      const data = await response.json();
      if (data) {
        setLoading(false);
        setProducts(data.products);
      } else {
        setProducts("PRODUCT LISTING DATA NOT FOUND");
      }
    } catch (error) {
      console.log(error);
    }
  };

  if (loading) {
    return <Loading loadingProductListing="Loading Product List" />;
  }

  const getProductID = () => {
    let foundProduct = {};
    foundProduct = products.find((item) => {
      return item.id === parseInt(id);
    });
    setSingleProduct(foundProduct);
  };

  // console.log("product ID = ", productID, typeof productID);
  console.log("products = ", products);
  console.log("singleproduct = ", singleProduct);

JSX

return (
    <>
      <div className="dvProducts col-12">
              <div className="row">
                <div className="col-12">
                  <NavLink
                    to="/product-listing"
                    className="text-dark mb-1 d-inline-block"
                  >
                    <i className="fa fa-angle-left f16"></i>
                    <span> Back</span>
                  </NavLink>
                </div>
                <div className="col-12 col-md-6 col-xl-4 mb-3">
                  <div className="border border-light shadow-sm p-1 h-100">
                    <div className="bg-light text-center p-5">
                      <a className="d-inline-block">
                        <img
                          src="images/description/coconut-water-200ml.png"
                          className="img-fluid"
                          alt="..."
                        />
                      </a>
                    </div>
                  </div>
                </div>
                <div className="col-12 col-md-6 col-xl-8 d-flex mb-3 mb-xl-0">
                  <div className="m-md-auto">
                    <div>
                      <h4>Coconut Water</h4>
                    </div>
                    <div className="mb-2">
                      <i className="fa fa-star text-warning d-inline-block"></i>
                      <i className="fa fa-star text-warning d-inline-block"></i>
                      <i className="fa fa-star text-warning d-inline-block"></i>
                      <i className="fa fa-star-o text-warning d-inline-block"></i>
                      <i className="fa fa-star-o text-warning d-inline-block"></i>
                    </div>
                    <div className="mb-3">
                      <p>
                        Every athlete's go to natural energy drink; Coconut
                        Water is a complete win-win for your everyday
                        rehydration needs. #iaminlovewiththecoco!
                      </p>
                    </div>
                    <div className="d-flex mb-3">
                      <div className="mr-2">
                        <h6 className="d-inline-block mb-1">Size:</h6>
                        <span className="d-inline-block">200ml</span>
                      </div>
                      <div className="mr-2 ml-2">
                        <h6 className="d-inline-block mb-1">Category:</h6>
                        <span className="d-inline-block">Juices</span>
                      </div>
                      <div className="ml-2">
                        <h6 className="d-inline-block mb-1">Price:</h6>
                        <span className="d-inline-block">
                          <i className="fa fa-inr"></i>
                          <span className="d-inline-block">40.00</span>
                        </span>
                      </div>
                    </div>
                    <div>
                      <button
                        className="btn btnSecondary"
                        href="detail.html"
                      >
                        Add to Bag
                      </button>
                    </div>
                  </div>
                </div>
              </div>
            </div>
    </>
  );
};

export default ProductDetail;

Upvotes: 7

Views: 20490

Answers (4)

Sajadox
Sajadox

Reputation: 96

use localstorage

npm install reactjs-localstorage

in your project :

import {reactLocalStorage} from 'reactjs-localstorage';

set and get your value everywhere you want

reactLocalStorage.set('var', true);
reactLocalStorage.get('var', true);
reactLocalStorage.setObject('var', {'test': 'test'});
reactLocalStorage.getObject('var');
reactLocalStorage.remove('var');
reactLocalStorage.clear();

source : https://www.npmjs.com/package/reactjs-localstorage

Upvotes: 1

Irfan Razzaq
Irfan Razzaq

Reputation: 51

You can't persist the data on page refresh with useState hook, better way is to pass that id as url params and check if there is any id in url then fetch the product. your single page route should accept a param like.

"/route/:id"

You can check this code snippet. How to set and get route params in react

Upvotes: 1

Ahmad Raza
Ahmad Raza

Reputation: 91

const getProductListingData = async () => {
try {
  const response = await fetch("http://localhost:8000/productListing");
  const data = await response.json();
  if (data) {
    setLoading(false);
    setProducts(data.products);
       // call this function after you are getting list of products
   getProductID(data.products);
   } else {
    setProducts("PRODUCT LISTING DATA NOT FOUND");
        
    }
 } catch (error) {
  console.log(error);
 }
 };

const getProductID = (tempProducts) => {
let foundProduct = {};
foundProduct = tempProducts.find((item) => {
  return item.id === parseInt(id);
});
setSingleProduct(foundProduct);
};

Upvotes: 2

Krzysztof Krzeszewski
Krzysztof Krzeszewski

Reputation: 6749

That's a normal behaviour, state is being reset on refresh per specification. If you want to preserve it you need to make use of localStorage/sessionStorage/cookies etc.

Which is best way?

Well I would say that the second approach is better. I would avoid keeping copy of state in localstorage. I would only keep some kind of token/id (in your case uid) which uniquely identify the user and would fetch fresh data every time. When your application grows it can be hard to manage those states in localstorage.

Upvotes: 5

Related Questions