-1

I'm trying to fetch the shop and it's coupons, I have two model one for the shop and one for the coupon, also two routers, one for fetching shops and one for fetching coupons, the shops are fetching fine and showing in client side, but the coupons are not showing in the client side. When /coupons/${shopName} I try it in postman it works fine, but in the client side not, I don't know why. Console log is giving me [object Object]

enter image description here

export default function ShopPage() {
  
  const [shop, setShop] = useState("");
  const shopName = useParams().shopName;
  const [coupons, setCoupons] = useState([]);

  useEffect(() => {
    const fetchShop = async () => {
      const res = await axios.get(`/shops/${shopName}`);
      setShop(res.data);
      console.log(res.data);
    };
    fetchShop();
  }, [shopName]);
  
  
  useEffect(() => {
    const fetchShopCoupons = async () => {
      const response = await axios.get(`/coupons/${shopName}`);
      setCoupons(response.data);
      console.log("Shop Coupons are:" + response.data);
    };
    fetchShopCoupons();
  }, []);

  return (
    <>

        <Box>
          <Stack>
          
            <Stack >
              <Avatar alt={(shop.shopName)} 
                    src={shop.shopPic}/>
            
              <Stack>
                <Box>
                  <Typography>
                      {shop.shopName}
                  </Typography>
                </Box>            
                </Box>
            </Stack>
        </Stack>
        <Box>
        <Coupons coupons={coupons}/>
        </Box>
        </Stack>
        </Box>
    </>
  )
}

Coupons Component:

export default function Coupons({ coupons = [] }) {

  const [filteredResults, setFilteredResults] = useState([]);
  const [searchInput, setSearchInput] = useState('');
  const [isLoading, setIsLoading] = useState(false);
  const filter = (e) => {
    const keyword = e.target.value;
      if (keyword !== '') {
          const filteredData = coupons.filter((coupon) => {
              return Object.values(coupon)
              .join('')
              .toLowerCase()
              .includes(searchInput.toLowerCase())
          })
          setFilteredResults(filteredData)
          
      } else {
        setFilteredResults(coupons);
      }
      setSearchInput(keyword);
  }
  console.log("filtered Coupons are:", filteredResults);

  return (
    <div className="coupons">
      <div className="couponsContainer">

      <div className="couponsSearchContainer">
            <div className="couponsSearch">
                  <div class="couponsSearchIconContainer">
                      <SearchIcon class="w-5 h-5" />
                  </div>
                    <input type="text"
                    className="couponsSearchInput"
                    placeholder="بحث"
                    name="couponSearchText"
                    id="couponSearchText"
                    onChange={filter}
                    />
              </div>
              {/* ENDS OF COUPONSSEARCHCONTAINER */}
      </div>
      {/* ENDS OF COUPONSSEARCH */}
    
      <div className="couponsBox">
      {isLoading ? (
          <Box sx={{ display: 'flex' }}>
            <CircularProgress />
          </Box>
      ) : (
        filteredResults.length > 0 ? (
          filteredResults.map((f) => (
            <Coupon coupon={f} />
          ))
          ) : (
            coupons.sort((a, b) => 
            new Date(b.createdAt) - new Date(a.createdAt))
            .map((c) => (
            <Coupon coupon={c} />
          )))
        )
        }
      </div>
      {/* ENDS OF COUPONSBOX */}

      </div>
      {/* ENDS OF COUPONSCONTAINER */}

    </div>
    //ENDS OF COUPONS
  );
}
sultan.h
  • 331
  • 1
  • 4
  • 16
  • 2
    *"Console log is giving me [object Object]"* That's the standard string you get when you use `+` to concatenate an *object* to a string. Instead of stumbling around in the dark with a `console.log` torch, I suggest *turning on the lights* using the debugger built into your IDE and/or browser. More [here](https://stackoverflow.com/questions/25385173/) and [here](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/). Apparently, `res.data` is an object. So you probably want some information from that object. – T.J. Crowder Nov 22 '22 at 10:01

2 Answers2

0

Maybe you could try response.data.value or response.data.value[0], its works for me.

Heliodor
  • 115
  • 6
  • How it worked for you? It didn't here – sultan.h Nov 22 '22 at 12:27
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Nov 24 '22 at 09:58
0

The problem can be with useEffect() you are using for fetching "shopCpupons". The dependency array of useEffect which fetches "shopCoupons" is empty('[]'), which means that that useEffect will immediately call the fetchShopCoupons() function as soon as the page loads, but at that time you will not have the "shopName" which is the endpoint you need in the fetchShopCoupons API call: const response = await axios.get(/coupons/$**{shopName}**);

1st Solution) So the solution is that in the 2nd useEffect which fetches shop coupons you can add "shopname" as dependency in dependency array, just like you did it in 1st useEffect which fetches shopdetails, The code can look like this

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
export default function ShopPage() {
  
  const [shop, setShop] = useState("");
  const shopName = useParams().shopName;
  const [coupons, setCoupons] = useState([]);

  useEffect(() => {
    const fetchShop = async () => {
      const res = await axios.get(`/shops/${shopName}`);
      setShop(res.data);
      console.log(res.data);
    };
    fetchShop();
  }, [shopName]);
  
  
  useEffect(() => {
    const fetchShopCoupons = async () => {
      const response = await axios.get(`/coupons/${shopName}`);
      setCoupons(response.data);
      console.log("Shop Coupons are:" + response.data);
    };
    fetchShopCoupons();
  }, [shopName]);

  return (
    <>

        <Box>
          <Stack>
          
            <Stack >
              <Avatar alt={(shop.shopName)} 
                    src={shop.shopPic}/>
            
              <Stack>
                <Box>
                  <Typography>
                      {shop.shopName}
                  </Typography>
                </Box>            
                </Box>
            </Stack>
        </Stack>
        <Box>
        <Coupons coupons={coupons}/>
        </Box>
        </Stack>
        </Box>
    </>
  )
}

Here I added 'shopname' as dependency in 2nd useEffect.

2nd Solution: or else you can use only one useEffect and control your shop and coupons variables like this

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
export default function ShopPage() {
  
  const [shop, setShop] = useState("");
  const shopName = useParams().shopName;
  const [coupons, setCoupons] = useState([]);

  useEffect(() => {
    const fetchShop = async () => {
      const res = await axios.get(`/shops/${shopName}`);
      setShop(res.data);
      console.log(res.data);
    };
    const fetchShopCoupons = async () => {
      const response = await axios.get(`/coupons/${shopName}`);
      setCoupons(response.data);
      console.log("Shop Coupons are:" + response.data);
    };
    fetchShop();
    fetchShopCoupons();
    
  }, [shopName]);

  return (
    <>

        <Box>
          <Stack>
          
            <Stack >
              <Avatar alt={(shop.shopName)} 
                    src={shop.shopPic}/>
            
              <Stack>
                <Box>
                  <Typography>
                      {shop.shopName}
                  </Typography>
                </Box>            
                </Box>
            </Stack>
        </Stack>
        <Box>
        <Coupons coupons={coupons}/>
        </Box>
        </Stack>
        </Box>
    </>
  )
}

Here as you can see I merged 2 useEffects into one useEffect as both your APIs are dependent upon "shopname" dependency, so once you will get shopname from params the program will first call the fetchShop() function which will fetch shop details and after that it will call fetchCoupons() which will call coupons for the shop. You can also rearrange the order of these function calls as per the requirements of project. This approach will make you code leaner and cleaner. However you can choose to use the best fit solutions out of 2 as per the requirement of the project.

  • please have a look at Coupons component filteredResults.length > 0 ? ( filteredResults.map((f) => ( )) ) : ( coupons.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt)) .map((c) => ( I think here is the problem .map is what causing the problem, i don't know if i'm getting this right or not – sultan.h Nov 24 '22 at 19:48
  • Can you explain what are you trying to do in this component, it will be much easier. – KARAN DOSHI Nov 25 '22 at 04:50
  • in this component i'm trying to show the coupons, there a search option above which filters the coupons when ever I type in the input, it work well in console log, but it won't show coupons in frontend maybe i'm using .map() wrong, i'm asking if its the right way to implement it or not. – sultan.h Nov 25 '22 at 05:56
  • Did you try the solution I gave, maybe it will resolve the issue. – KARAN DOSHI Nov 25 '22 at 07:35