I make an ecommerce site I am trying to display the page with the details of a product:
import React, { useState, useEffect } from "react";
import Link from "next/link";
import { useRouter } from "next/router";
import axios from "axios";
import Layout from "../components/Layout";
const ProductPage = () => {
const router = useRouter();
const [product, setProduct] = useState({});
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchProduct = async () => {
try {
const response = await axios.get(`/api/products?id=${router.query.id}`);
const currentProduct = response.data;
setLoading(false);
setProduct(currentProduct);
} catch (error) {
console.error(error);
}
};
fetchProduct();
}, [router.query.id]);
return (
<Layout title={product.name}>
{loading ? (
<div className="text-center">Loading...</div>
) : (
<div className="max-w-lg mx-auto p-5">
<h1 className="text-2xl font-bold mb-5">{product.name}</h1>
<img
src={product.imageUrl}
alt={product.name}
className="w-full mb-5"
/>
<p className="mb-5">{product.description}</p>
<p className="text-xl font-bold mb-5">
Price: {product.price}
</p>
<Link href="/" legacyBehavior>
<a className="btn btn-primary">Go back to the products list</a>
</Link>
</div>
)}
</Layout>
);
};
export default ProductPage;
The values are not displayed so I put some console.log When I put a console.log in the "try" product returns an empty object, and when I put the console.log after the useffect the product returns an object with my values
CodePudding user response:
You need to set the "isLoading" state in false whene the "product" state when the state has finished setting. In order to do that you need to add 1 more useEffect to listen for changes in the product state, for that you must add the "product" state as a dependency of the useEffect.
Try the next code:
import React, { useState, useEffect } from "react";
import Link from "next/link";
import { useRouter } from "next/router";
import axios from "axios";
import Layout from "../components/Layout";
const ProductPage = () => {
const router = useRouter();
const [product, setProduct] = useState({});
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchProduct = async () => {
try {
const response = await axios.get(`/api/products?id=${router.query.id}`);
const currentProduct = response.data;
setProduct(currentProduct);
} catch (error) {
console.error(error);
}
};
fetchProduct();
}, [router.query.id]);
useEffect(() => {
setLoading(false);
}, [product]);
return (
<Layout title={product.name}>
{loading ? (
<div className="text-center">Loading...</div>
) : (
<div className="max-w-lg mx-auto p-5">
<h1 className="text-2xl font-bold mb-5">{product.name}</h1>
<img
src={product.imageUrl}
alt={product.name}
className="w-full mb-5"
/>
<p className="mb-5">{product.description}</p>
<p className="text-xl font-bold mb-5">Price: {product.price}</p>
<Link href="/" legacyBehavior>
<a className="btn btn-primary">Go back to the products list</a>
</Link>
</div>
)}
</Layout>
);
};
export default ProductPage;
CodePudding user response:
useState
hook does not update the state value instantly. There are a lot of things happening when you change the state, like batching state updates, recomputing DOM manipulations, re-rendering components, etc.
If you want to know what is going to be set as your state, log the argument that you are passing to the setProduct
function. You may also use React dev tools.