Why array find returns nothing? using context and params

41 Views Asked by At

i have this page component for each product information:

export default function Product() {
  const { data } = useContext(ShopContext);
  const { id } = useParams();
  
  if (!data) {
    return <div>Loading product...</div>;
  }

  const product = data.find((item) => item.id === id);

  return (
    <div>
      {product.title}
    </div>
  );
}

somehow product is undefined though data and id can be logged into console and their value is available, i made sure of it like this:

export default function Product() {
    const { data } = useContext(ShopContext);
    const { id } = useParams();

    if (!data) {
      return <div>Loading product...</div>;
    }

    const product = data.find((item) => item.id === id);
    
    return (
    <div>
      <div>{id}</div>        {/*this div is displayed as expected*/}
      <div>                  {/*this div is displayed as expected*/}
        {data.map((item) => (
          <div key={item.id}>{item.title}</div>
        ))}
      </div>
      <div>{product?.title}</div>       {/*this div is empty*/}
    </div>
  );
  }

for additional information i'm fetching the data from fakestoreapi.com in the app component and it works fine in other components. here's the fetching piece:

useEffect(() => {
    async function FetchData() {
      try {
        const response = await fetch("https://fakestoreapi.com/products");
        if (!response.ok) {
          throw new Error(`HTTP error: Status ${response.status}`);
        }
        let postsData = await response.json();
        postsData.sort((a, b) => {
          const nameA = a.title.toLowerCase();
          const nameB = b.title.toLowerCase();
          return nameA.localeCompare(nameB);
        });
        setData(postsData);
        setError(null);
      } catch (err) {
        setData(null);
        setError(err.message);
      } finally {
        setLoading(false);
      }
    }

    FetchData();
  }, []);

this is the context:


import { createContext } from "react";

export const ShopContext = createContext({
  data: [],
  loading: true,
  error: "",
  setData: () => {},
  cart: [],
  addToCart: () => {},
  removeFromCart: () => {},
});

and this is its states in app component:

const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [cart, setCart] = useState([]);

const addToCart = (productId) => {
  ....
};

const removeFromCart = (productId) => {
  .....
};

return (
    <ShopContext.Provider
      value={{
        data,
        loading,
        error,
        setData,
        cart,
        addToCart,
        removeFromCart,
      }}
    >
      <Header />
      <Body />
      <Footer />
    </ShopContext.Provider>
  );

okay i figured out that i was using === and ids had different types. i'm stupid yay


  const product = data.find((item) => item.id === Number(id));

1

There are 1 best solutions below

5
YATIN GUPTA On

I have replicated some part of code to illustrate you what mistake your are doing and how you can correct it.

context.jsx

import {createContext, useState} from 'react';

export const ShopContext = createContext();
const ShopProvider =  ({ children }) => {
  const [data, setData] = useState([]);

  const defaultContext = {
    data,
    setData,
  };

  return (
    <ShopContext.Provider value={defaultContext}>
      {children}
    </ShopContext.Provider>
  );
};
export default ShopProvider;

index.jsx

import React from 'react';
import ReactDOM from 'react-dom/client';
import ShopProvider from './context';

import { App } from './App.jsx'

ReactDOM.createRoot( 
  document.querySelector('#root')
).render(<ShopProvider><App /></ShopProvider>)

App.jsx

import React, {useContext, useEffect } from 'react';
import {ShopContext} from './context';
import Product from './Product';

export function App(props) {
  const {setData} = useContext(ShopContext); // So you require to get setter method from context.
  useEffect(() => {
    async function FetchData() {
      try {
        const response = await fetch("https://fakestoreapi.com/products");
        if (!response.ok) {
          throw new Error(`HTTP error: Status ${response.status}`);
        }
        let postsData = await response.json();
        postsData.sort((a, b) => {
          const nameA = a.title.toLowerCase();
          const nameB = b.title.toLowerCase();
          return nameA.localeCompare(nameB);
        });
        setData(postsData);
      } catch (err) {
        setData([]);
      }
    }
    FetchData();
  }, []);
  return (
      <div className='App'>
        <Product />
      </div>
  );
}

Product.jsx

import {useContext} from 'react';
import {ShopContext} from './context';

export default function Product() {
  const { data } = useContext(ShopContext);
  const id = 1;
  
  if (!data) {
    return <div>Loading product...</div>;
  }

  const product = data.find((item) => item?.id === id);

  return (
    <div>
      {product?.title}
    </div>
  );
}

Let me know if you face any problem in understanding this illustration.