Im trying to create a little marketplace website for a project which will use stripe Checkout. I've been following a tutorial however it didn't cover using products from an API. This is where i got stuck.
So firstly my table in the api which contains the product has these fields: oid | listingTitle | itemDescription | categorySelection | imageSelection | userEmail | userPhoneNumber
This all works perfectly however apart one thing. In the product useState im trying to use these fields from the database to store the name description and price which will then be sent to stripe itsel. However when sending the payment in the itemDescription it will say "undefined" the same in name etc. Apart from price because i set it to 80 just to test.
Now my question is how i can access the fields from the api with the info in the product useState i have my whole code below:
function Item({match}) {
useEffect(() => {
fetchItem();
console.log(match)
},[]);
const [item, setItem]= useState([]);
const fetchItem= async ()=>{
const fetchItem= await fetch (`http://link //?oid=${match.params.oid}`
);
const item= await fetchItem.json();
setItem(item.rows[0])
console.log(item)
}
toast.configure()
const [product] = useState({
name: item.listingTitle,
price: "80",
description: item.itemDescription,
});
console.log(product.name)
async function handleToken(token, addresses) {
const response = await axios.post(
"http://localhost:8080/checkout",
{ token, product }
);
console.log(response.status)
if (response.status === 200) {
toast("Success! Check email for details", { type: "success" });
} else {
toast("Something went wrong", { type: "error" });
}
}
return (
<div className="App">
<div className="container">
<h1 key={item.oid}></h1>
<br />
<br />
<h1 className="text-center">Stripe Checkout</h1>
<br />
<h2 className="text-center">Product Info:</h2>
<h3 className="text-center">Product Name: {item.listingTitle}</h3>
<h3 className="text-center">Product Price: {item.itemPrice}</h3>
<img className="image" src={[item.imageSelection]}width={250} height={150}></img>
<h3 className="text-center">
Product Description: {item.itemDescription}
</h3>
<br />
<div className="form-group container">
<StripeCheckout
className="center"
stripeKey=""
token={handleToken}
amount={item.itemPrice * 100}
name={item.listingTitle}
billingAddress
shippingAddress
/>
</div>
</div>
</div>
);
}
CodePudding user response:
this is the common problem every react newbies face , the problem here is setState functions dont update values instantly instead it gets submitted to react core system and later assigned to that state after all the codes executed so if you console.log a state in next line just after setting it you will get either old value or undefined
thats why useEffect hook is here to help
to track one state and use its value in other state you have to use useEffect hook like this ex: useEffect(()=>{},[stateToTrack])
here i have also written a demo in sandbox you can check and play hope this will help demo
import { useEffect, useState } from "react";
import "./styles.css";
export default function App() {
const [item, setItem] = useState([]);
function fetchItem() {
fetch("https://jsonplaceholder.typicode.com/posts/1")
.then((r) => r.json())
.then((r) => {
setItem(r);
});
}
const [product, setProduct] = useState({
name: "",
desc: ""
});
useEffect(fetchItem, []); // run once
useEffect(() => {
// tracking item state
setProduct({
name: item.title,
desc: item.body
});
console.log(item);
}, [item]);
return (
<>
<div style={{ fontSize: 20, fontWeight: "bold" }}>{product.name}</div>
<br />
<div>{product.desc}</div>
</>
);
}
CodePudding user response:
Kinda fundamental feature of Javascript; if you don't know what it is, very important to go learn it. Essentially it "wraps" a function in it's local environment and lets it run somewhat-independently - for simplest example, (() => {fetchItem()})
simply returns an anonymous function to be run; (() => {fetchItem()})();
creates it and runs it.
You have other issues, so probably closer to this (assuming you only wanted to run toast.configure() once)
function Item({match}) {
const [item, setItem]= useState([]);
const [product, setProduct] = useState({
name: item.listingTitle,
price: "80",
description: item.itemDescription,
});
useEffect(() => {
toast.configure()
(async () => {
const fetchItem= await fetch (`http://link //?oid=${match.params.oid}`);
const item= await fetchItem.json();
setItem(item.rows[0])
console.log(item)
})();
console.log(match)
},[match]);
console.log(product.name)
async function handleToken(token, addresses) {
const response = await axios.post(
"http://localhost:8080/checkout",
{ token, product }
);
console.log(response.status)
if (response.status === 200) {
toast("Success! Check email for details", { type: "success" });
} else {
toast("Something went wrong", { type: "error" });
}
}
return (
<div className="App">
<div className="container">
<h1 key={item.oid}></h1>
<br />
<br />
<h1 className="text-center">Stripe Checkout</h1>
<br />
<h2 className="text-center">Product Info:</h2>
<h3 className="text-center">Product Name: {item.listingTitle}</h3>
<h3 className="text-center">Product Price: {item.itemPrice}</h3>
<img className="image" src={[item.imageSelection]}width={250} height={150}></img>
<h3 className="text-center">
Product Description: {item.itemDescription}
</h3>
<br />
<div className="form-group container">
<StripeCheckout
className="center"
stripeKey=""
token={handleToken}
amount={item.itemPrice * 100}
name={item.listingTitle}
billingAddress
shippingAddress
/>
</div>
</div>
</div>
);
}