When I try to show the height and weight from an API (http://thedogapi.com/), I get an error:
TypeError: Cannot read properties of undefined (reading 'metric')
If I comment the "items.height.metric" everything works great, but I have to show these results also.
From a page before I get the ID, as I click on an item from a list, that brings me to the second page, showing something like "http://localhost:3000/config/?id=2" (So, I clicked on the second item).
GitHub: https://github.com/fvrabelo/tiroNewDogApi
Any help? love y'all
enter image description here
import {React} from 'react'
import {useEffect, useState} from 'react';
import {Link} from 'react-router-dom'
const Page = () =>{
// identifica ID na url
const urlParams = new URLSearchParams(window.location.search);
const id = urlParams.get('id');
// fetch da raca baseado no ID passado pela url
const [items, setItems] = useState([])
useEffect(() => {
const getBreeds = async () =>{
const res = await fetch(
`https://api.thedogapi.com/v1/breeds/${id}`
);
const data = await res.json();
setItems(data)
}
getBreeds()
}, [])
//fetch da imagem
function getImage(imageId) {
fetch(`https://api.thedogapi.com/v1/images/${imageId}`)
.then(r =>r.json())
.then(response=> {
const data = response
document.querySelector(".image").src = data.url;
})
}
return(
<div className=""
style={{"display": "flex",
"position":"relative",
"justify-content": "center",
"align-items": "center",
'flex-direction': "column",
"maxWidth":"100%",
"maxHeight":"100%"}}>
<h6 className="card-subtitle mb-2 text-muted text-center" style={{"marginTop":"5px"}}>Breed name</h6>
<h5 className="card-title text-center">{items.name}</h5>
<h6 className="card-subtitle mb-2 text-muted text-center" style={{"marginTop":"5px"}}>Bred for</h6>
<h5 className="card-title text-center">{items.bred_for}</h5>
<h6 className="card-subtitle mb-2 text-muted text-center" style={{"marginTop":"5px"}}>Group</h6>
<h5 className="card-title text-center">{items.breed_group}</h5>
<h6 className="card-subtitle mb-2 text-muted text-center" style={{"marginTop":"5px"}}>Temperament</h6>
<h5 className="card-title text-center">{items.temperament}</h5>
<h6 className="card-subtitle mb-2 text-muted text-center" style={{"marginTop":"5px"}}>Life span</h6>
<h5 className="card-title text-center">{items.life_span}</h5>
<h6 className="card-subtitle mb-2 text-muted text-center" style={{"marginTop":"5px"}}>Height</h6>
<h5 className="card-title text-center">{items.height.metric}</h5>
<h6 className="card-subtitle mb-2 text-muted text-center" style={{"marginTop":"5px"}}>Weight</h6>
<h5 className="card-title text-center">{items.weight.metric}</h5>
<img className ="image"
src={getImage(items.reference_image_id) }
style={{ "maxHeight": "300px", "maxWidth": "300px", "marginBottom":"15px" }}/>
<Link to="/" className="btn btn-primary">Home</Link>
</div>
);
}
export default Page;
<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>
For now I have something like this:
enter image description here
This could be because the fields height.metric do not exist for some dogs (and for others they do).
So you have to handle that possibility:
{ items.height.metric &&
<h6 className="card-subtitle mb-2 text-muted text-center" style={{"marginTop":"5px"}}>Height</h6>
<h5 className="card-title text-center">{items.height.metric}</h5>
}
{ items.weight.metric &&
<h6 className="card-subtitle mb-2 text-muted text-center" style={{"marginTop":"5px"}}>Weight</h6>
<h5 className="card-title text-center">{items.weight.metric}</h5>
}
Related
it is the initial state of the redux toolkit, cartSlice and it is an object and products is an array having oneProduct as an object containing product information like image, price, description, etc.
This is cart slice
import { createSlice } from "#reduxjs/toolkit";
const cartSlice = createSlice({
name: "cart",
initialState: {
products: [],
quantity: 0,
total: 0,
},
reducers: {
addProduct: (state, action) => {
state.products.push(action.payload);
state.quantity += 1;
state.total += action.payload.price * action.payload.quantity;
},
removeProduct: (state, action) => {
let index = state.products.indexOf(action.payload)
state.quantity -= action.payload
state.products.splice(index, 1)
}
},
});
export const { addProduct ,removeProduct} = cartSlice.actions;
export default cartSlice.reducer;
THIS OBJECT IS initilaState of redux. In CONSOLE OF BROWSER
Object
products
:
Array(2)
0
:
{status: 'Specific products is here', oneProduct: {…}}
1
:
{status: 'Specific products is here', oneProduct: {…}}
length
:
2
[[Prototype]]
:
Array(0)
quantity
:
2
total
:
NaN
[[Prototype]]
:
Object
The problem is I am unable to map products array console above . Below is the code for the orders page and kindly Look at map Method
import React, { useState } from 'react'
import { Link } from 'react-router-dom';
import { useSelector } from 'react-redux';
const Order = () => {
const cart = useSelector((state) => state.cart)
console.log(cart)
const quantity = useSelector((state) => state.cart.quantity)
const [counter, setCounter] = useState(1);
const counterNumber = (type) => {
if (type === "inc") {
setCounter((prev) => prev + 1);
} else {
counter > 1 && setCounter((prev) => prev - 1);
}
};
return (
<>
<h1 className='font-bold text-xl text-center my-5'>CART PAGE</h1>
<div className='flex justify-around flex-wrap my-5 space-x-2'>
<div className='flex flex-col shadow-md p-2'>
{cart.products.oneProduct?.map((item)=>(
<div className="Product_info flex align-middle m-auto space-x-2 ">
<div className="product_image my-auto" key={item._id}>
<img src={item.img} alt="" className='w-16 h-16 ' />
</div>
<div className="details">
<h1 className='font-bold text-lg m-3'>{item.title}</h1>
</div>
<div className="price my-auto ">
<h1 className='font-bold text-2xl cursor-pointer'>$ {item.price}</h1>
</div>
<div className="ince_dec flex align-middle justify-center space-x-2 mr-5">
<div className="dec font-extrabold text-3xl my-auto" onClick={() => counterNumber("dec")}>-</div>
<h1 className='font-bold text-2xl my-auto'> {counter} </h1>
<div className="inc font-extrabold text-3xl my-auto cursor-pointer" onClick={() => counterNumber("inc")}>+</div>
</div>
<hr />
</div>
))}
</div>
<div className=" sideCart ml-1 text-white bg-blue-400 p-10 ">
<h1 className="text-center text-black font-extrabold">Product Quantity is: </h1>
<div className="text-white text-center font-bold my-2">{cart.products.length<1 ?"Cart is empty": quantity }</div>
<ul >
<div className="items flex align-middle items-center ">
</div>
</ul>
<div className="bton flex justify-center align-middle">
<Link to="/checkout">
<button className=" cart flex ml-4 text-white bg-black border-0 py-2 px-4 focus:outline-none lg:w-32 hover:bg-indigo-600 rounded md:w-4 md:px-6 text-sm">Checkout Now</button>
</Link>
</div>
</div>
</div>
</>
)
}
export default Order
Problem: Error: Hydration failed because the initial UI does not match what was rendered on the server.
How can I iterate the cart without having to create another state :c
const initialState = {
cart: Cookies.get("cart") ? JSON.parse(Cookies.get("cart")) : [],
loading: null,
error: null,
};
import Layout from "../../Layout";
import { connect } from "react-redux";
import { removeFromCart, clearCart } from "../../redux/actions/cart";
function PasarelaPago({ loading, removeFromCart, clearCart, cart }) {
return (
<Layout>
<div className="px-2 py-10">
<h1 className="text-2xl text-gray-600 font-bold tracking-wider text-center">
Pasarela de pago
</h1>
<div className="w-full lg:w-1/2 mx-auto">
<h3 className="text-lg font-light tracking-widest text-gray-500 px-4 my-4">
Tu bolsa de compras
</h3>
<div className="flex justify-between px-3 text-xs text-gray-400 border-b pb-2">
<div>PRODUCTOS</div>
<div>CANTIDAD</div>
<div>TOTAL</div>
</div>
<div className="flex flex-col gap-3">
ERROR!!
{cart && cart.map((item) => <div>{item.name}</div>)}
</div>
</div>
</div>
</Layout>
);
}
const mapStateToProps = (state) => ({
loading: state.Cart.loading,
cart: state.Cart.cart,
});
export default connect(mapStateToProps, {
removeFromCart,
clearCart,
})(PasarelaPago);
I'm trying to create a blog with Node.js, React and graphql. I'm new to all those technologies (including Java-/Typescript itself). I'd greatly appreciate your help.
Currently I'm stuck getting the data of my articles to show.
In the function getStaticProps I can read the data of my graphql response fine.
But when I pass that data as a parameter to the React component (as getStaticProps provides that data during build-time) I can't access that data anymore and get the error message "TypeError: Cannot read properties of undefined (reading 'articles')".
Below is my code:
import {GetStaticProps} from "next";
import {serverSideTranslations} from "next-i18next/serverSideTranslations";
import {ssrGetBlog} from "../../generated/page";
// #ts-ignore implicitly has any type
export default function Index(data) {
console.log(data.attributes) //TypeError: Cannot read properties of undefined (reading 'articles')
// below in getStaticProps this worked!?
return (
<div className="relative bg-gray-50 px-4 pt-16 pb-20 sm:px-6 lg:px-8 lg:pt-24 lg:pb-28">
<div className="absolute inset-0">
<div className="h-1/3 bg-white sm:h-2/3"/>
</div>
<div className="relative mx-auto max-w-7xl">
<div className="text-center">
<h2 className="text-3xl font-bold tracking-tight text-gray-900 sm:text-4xl">
{data.blogHeading}
</h2>
<p className="mx-auto mt-3 max-w-2xl text-xl text-gray-500 sm:mt-4">
{data.blogDescription}
</p>
</div>
<div className="mx-auto mt-12 grid max-w-lg gap-5 lg:max-w-none lg:grid-cols-3">
{data.attributes.articles.data.map((article) => (
<div
key={article.attributes.title}
className="flex flex-col overflow-hidden rounded-lg shadow-lg"
>
<div className="flex-shrink-0">
<img
className="h-48 w-full object-cover"
src={article.attributes.articleImg.data.attributes.url}
alt=""
/>
</div>
<div className="flex flex-1 flex-col justify-between bg-white p-6">
<div className="flex-1">
<p className="text-sm font-medium text-indigo-600">
<a href={"not implemented: article.attributes.articleCategory.data.attributes.slug"} className="hover:underline">
{"none existent: article.attributes.articleCategory.data.attributes.categoryName"}
</a>
</p>
<a href={article.attributes.slug} className="mt-2 block">
<p className="text-xl font-semibold text-gray-900">
{article.attributes.title}
</p>
<p className="mt-3 text-base text-gray-500">
{article.attributes.shortDescription}
</p>
</a>
</div>
<div className="mt-6 flex items-center">
<div className="flex-shrink-0">
<a href={"not implemented: article.attributes.author.href"}>
<span className="sr-only">{"not implemented: article.author.authorName"}</span>
<img
className="h-10 w-10 rounded-full"
src={"not implemented: article.attributes.author.authorImg"}
alt=""
/>
</a>
</div>
<div className="ml-3">
<p className="text-sm font-medium text-gray-900">
<a href={"not implemented: article.attributes.author.authorUrl"} className="hover:underline">
{"not implemented: article.attributes.author.name"}
</a>
</p>
<div className="flex space-x-1 text-sm text-gray-500">
<time dateTime={article.attributes.publishedOn}>{article.attributes.publishedOn}</time>
<span aria-hidden="true">·</span>
<span>{"not implemented: article.attributes.readingTime"} read</span>
</div>
</div>
</div>
</div>
</div>
))}
</div>
</div>
</div>
);
}
export const getStaticProps: GetStaticProps = async (context) => {
const {locale} = context;
// #ts-ignore
const blogQuery = await ssrGetBlog.getServerPage({}, context);
const data = blogQuery.props.data?.blog?.data; //props.data?.blog?.data?.attributes;
//console.log(data); // works fine
//console.log(data.attributes.articles.data[0]); // works fine
return {
props: {
data,
...(await serverSideTranslations(locale || "", ["common"])),
},
};
};
Try this, maybe you're not accessing the component's props properly
export default function Index(props) {
console.log(props.data.attributes)
}
or
export default function Index({ data }) {
console.log(data.attributes)
}
export const getStaticProps: GetStaticProps = async (context) => {
const {locale} = context;
// #ts-ignore
const blogQuery = await ssrGetBlog.getServerPage({}, context);
const data = blogQuery.props.data?.blog?.data; //props.data?.blog?.data?.attributes;
//console.log(data); // works fine
//console.log(data.attributes.articles.data[0]); // works fine
const comething = await serverSideTranslations(locale || "", ["common"])
return {
props: {
data,
...comething,
},
};
};
Try this maybe?
import React from "react";
import { useParams } from "react-router-dom";
import Spinner from "../Spinner/Spinner";
import { useState } from "react";
import { useEffect } from "react";
const InventoryItemDetail = () => {
const [spinner, setSpinner] = useState(false);
const [itemDetail, setItemDetail] = useState({});
**const [newQuantity, setNewQuantity] = useState(itemDetail.quantity)**;
let { itemId } = useParams();
useEffect(() => {
setSpinner(true);
fetch(`http://localhost:5000/item/${itemId}`)
.then((res) => res.json())
.then((data) => setItemDetail(data));
setSpinner(false);
}, [itemId]);
if (spinner) {
return <Spinner />;
}
const handleRestock = (e) => {
e.preventDefault();
console.log(e.target.restock.value);
};
const handleDeleveredByOne = () => {
setNewQuantity(itemDetail.quantity - 1);
};
return (
<div className="bg-[#F0ECE3] lg:h-screen ">
<div className="w-11/12 mx-auto grid md:grid-cols-2 lg:grid-cols-3 justify-items-center items-center pt-32">
<div className="lg:w-[500px] ">
<img src={itemDetail.img} alt="" />
</div>
<div className="px-2 font-poppins mb-16 md:col-span-1 lg:col-span-2">
<div className="lg:w-3/6 border-2 border-red-500 mx-auto px-12 py-16">
<p className="text-xl py-2 font-bold">{itemDetail.name}</p>
<p className="">{itemDetail.shortDescripton}</p>
<p>
{" "}
Quantity: <span className="font-bold">{newQuantity}</span>
</p>
<p>
Price:{" "}
<span className="text-red-500 text-xl font-blod">
{" "}
${itemDetail.price}
</span>
</p>
<p className="font-light text-sm">
Supplier: {itemDetail.supplierName}
</p>
<button
onClick={handleDeleveredByOne}
className="mt-8 border-2 border-red-500 py-2 lg:px-6 w-full lg:w-fit hover:bg-red-500 hover:text-white"
>
Delivered
</button>
<form
onSubmit={handleRestock}
className="flex justify-end mt-8 lg:mt-0"
>
<div className="grid grid-cols-2 border-2 border-red-500 py-2 px-4 hover:bg-red-500 ">
<input
className="lg:w-20 text-lg order-2 outline-none "
type="number"
name="restock"
id=""
/>
<input
className="hover:text-white cursor-pointer"
type="submit"
value="Restock"
/>
</div>
</form>
</div>
</div>
</div>
</div>
);
};
export default InventoryItemDetail;
I want to display quantity that I have received from backend server and by clicking on delivered button, everytime it will reduce by one and save it to backend server. I have tried but it does not display quantity information and after clicking button it only works for first time.
How can I display quantity information and that I received from backend server and how to reduce it on every click and save it to backend server.
I don't understand why I'm getting this error. I want to understand what's wrong with the following code.
const Book = ({ book }) => {
const navigate = useNavigate()
const { _id, name, des, price, quantity, img, sName } = book;
return (
<div className='bg-white rounded-xl p-5'>
<div className='p-5'>
<img className='rounded-xl hover:shadow-2xl hover:shadow-black transition ease-in-
out hover:scale-110 duration-700' src={img} alt="" />
</div>
<h4 className='text-xl text-red-400 font-serif my-5'>{name}</h4>
<h6 className='text-red-400 text-xl font-serif py-3'>Price : ${price}</h6>
<h6 className=' flex justify-between px-5 font-semibold text-gray-500 font-serif'>
<span className=''>Stock in : {quantity}</span>
<span>Supply by {sName}</span>
</h6>
</div>