What is wrong with my useEffect()? It return empty object

Viewed 1176

I'm trying to fetch data from my server, I've tested the data fetching using Postman, everything is fine. I also double checked whether my API path was wrong, also not the issue.

I changed useEffect to useLayoutEffect, also no luck. I created a separate function outside the useEffect hook, also not working. I created console.log("I was here") on every single line, where each log was successfully printed inside the fetchProduct function.

Now I'm so stuck. I suspect the effects finish before the promise returns. Thank you in advance.

ProductDetail component

import React, { useEffect, useState } from "react"
import EcommerceLayoutsTypeFourteenth from "../layouts/Ecommerce/EcommerceLayoutsTypeFourteenth/EcommerceLayoutsTypeFourteenth"
import EcommerceLayoutsTypeSecond from "../layouts/Ecommerce/EcommerceLayoutsTypeSecond/EcommerceLayoutsTypeSecond"
import axios from "axios"

const ProductDetail = ({ match, products }) => {
  const [product, setProduct] = useState({})

  useEffect(() => {
    const fetchProduct = async () => {
      const response = await axios.get(`/api/products/${match.params.id}`)
      setProduct(response.data)
    }
    fetchProduct()
  }, [match])

  return (
    <>
      <EcommerceLayoutsTypeSecond product={product} />
      <EcommerceLayoutsTypeFourteenth products={products} />
    </>
  )
}

export default ProductDetail

This is my App.js

import React, { useState, useEffect } from "react"

import { BrowserRouter as Router, Route, Switch } from "react-router-dom"
import Container from "reactstrap/lib/Container"
import FootersLayoutsTypeEighth from "./layouts/FootersLayouts/FootersLayoutsTypeEighth/FootersLayoutsTypeEighth"
import Header from "./layouts/HeaderLayouts/Header.js"
import HomeScreen from "./screens/HomeScreen"
import ProductDetail from "./screens/ProductDetail"
import axios from "axios"

const App = () => {
  const [products, setProducts] = useState([])

  useEffect(() => {
    const fetchProducts = async () => {
      const response = await axios.get("/api/products/")
      setProducts(response.data)
    }
    fetchProducts()
  }, [])

  return (
    <Router>
      <Container>
        <Header dark={false} />
      </Container>
      <Switch>
        <Route
          exact
          path="/"
          render={(props) => <HomeScreen {...props} products={products} />}
        />
        <Route
          path="/products/:id"
          render={(props) => <ProductDetail {...props} products={products} />}
        />
      </Switch>
      <FootersLayoutsTypeEighth />
    </Router>
  )
}

export default App
3 Answers

Inside the object got and array for category, it look like this..

    const products = [{
    _id: 1,
    title: "GP Base Coat",
    description:
      "FLINKENĀ® Based Coat mortar is produced according to the requirement of BS EN 998-1; incorporating standardized binder, well graded silica sand, water retention ability additve for all types of brick and block rendering.",
    price: "40.00",
    poster: "./image/flinken-product-01.png",
    category: "gp-series",
    link: "/products/1",
    features: [
      "feature 1",
      "feature 2",
      "feature 3",
      "feature 4",
      "feature 5",
      "feature 6",
    ],
    rating: 4.5,
  },...]

So every-time i call the products.features[0] the data inside my products state will become empty object.. so the solution here i just create state for features and products separately..

  const [product, setProduct] = useState({})
  const [feature, setFeature] = useState([])

  useEffect(() => {
    const fetchData = async () => {
      const { data } = await axios.get(`/api/products/${id}`)
      setFeature(data.features)
      setProduct(data)
    }
    fetchData()
  }, [id])

thank you to all of you that contribute your time and effort to help me last week, i really appreciate all of you!

Try to wrap it up in anonymous async function like this

useEffect(() => {
    (async () => {
        const response = await axios.get("/api/products/")
        const json = await response.json()
        setProducts(json)
    })()
}, [])

Also, keep in mind that whenever you're creating an "async" function, you need to resolve the promise. So if your function is constructed like this

const fetchProduct = async () => {
  const response = await axios.get(`/api/products/${match.params.id}`)
  const json = await response.json()
  return json;
}

You need to resolve it like this

fetchProduct.then((data) => // do something)

Or you can resolve it under anonymous async function like this

const data = await fetchProduct()

why didnt you setProduct like this:

await axios.get(`/api/products/${match.params.id}`).then((res) => setProduct(res.data));

an async/await function return a Promise so maybe you can't get product when set product from response outside.

Related