Showing Data in React Native with useParams - reactjs

I've the following question, how can I display the data in react-native with useparams? I've the following code snippet in my Details.jsx
import React from 'react'
import {useParams} from 'react-router-dom'
const Details = () => {
const userData = JSON.parse(localStorage.getItem('user'))
const token = userData ? userData.accessToken : null
const params = useParams()
const [load, setLoad] = React.useState(false)
const getAccountDetails = React.useCallback(async () => {
setLoad(true)
await fetch (`http://localhost:4000/api/account/findonecard/${params.idCard}`, {
headers: {
'Authorization': `Bearer ${token}`
}
}).then(res => res.json()).then(response=>{
console.log(response)
//My response drops the data I need
})
}, [])
React.useEffect(() => {
getAccountDetails()
}, [getAccountDetails])
return (
<>
<div>Details</div>
{
!load ?
(
<Detail card={{
username: card.fullname,
description: card.description,
mainPic: card.pic_profile,
userTags: card.usertags
}} />
)
:
(
<div style={{ position: 'relative', zIndex: 99, color: '#000000', fontFamily: 'sans-serif', textAlign: 'center', margin: '60px auto' }}>No Card to show</div>
)
}
</>
)
}
export default Details
This releases an object with my data, such as photo, description, name, etc.
Although I tried to loop through the object, I can't display the data on my Front, what am I missing?
This is my Detail.jsx
const Detail = ({ card }) => {
return (
<div className="content">
<div className="content_card-container">
<ShowMore/>
<h2 className="content_card-username">{card.username}</h2>
<div
className="content_card-image"
style={{
backgroundImage:
`url(${card.cardImg})`
}}
/>
<div className="content_tags-slider">
<SliderComponent tags={card.userTags} />
</div>
</div>
<div className="content_user-description">
<p className="content_user-description-text">{card.description}</p>
</div>
<div className="content_choice-container">
<img src={Dislike} alt="" className="content_choice-icon" />
<img src={Like} alt="" className="content_choice-icon" />
</div>
</div>
);
};

To keep track of the account details we'll create a state.
const [accountDetails, setAccountDetails] = useState({});
In the getAccountDetails function you can set the state with the received data from the api. You're also mix 'n matching await and then, you should use one. Lets go with await for this one
const getAccountDetails = React.useCallback(async () => {
setLoad(true);
const response = await fetch(
`http://localhost:4000/api/account/findonecard/${params.idCard}`,
{
headers: {
Authorization: `Bearer ${token}`,
},
}
);
const data = await response.json();
// console.log(data);
setAccountDetails(data);
setLoad(false); // set load to false
}, []);
When passing the card data down to the Detail component we can use the accountDetails like so
<Detail
card={{
username: accountDetails.fullname,
description: accountDetails.description,
mainPic: accountDetails.pic_profile,
userTags: accountDetails.usertags,
}}
/>
You maybe want to set the initital state of load to true

Related

How to pass id from page to another? [duplicate]

This question already has answers here:
How to pass data from a page to another page using react router
(5 answers)
Closed 5 months ago.
I have 2 pages: (Datatable.jsx and Single.jsx).
I need to send id from Datatable.jsx to Single.jsx. After googling, i found that i can do that by using the <Link /> component, like this:
<Link
to={{
pathname: "/page",
state: data
}}
>
And then you can access the desired sent data to the second page:
render() {
const { state } = this.props.location
return (
// render logic here
)
}
I dont know how to apply this on my two pages:
Datatable.jsx:
//...
const Datatable = () => {
const [data, setData] = useState([]);
const handleDelete = (id) => {
setData(data.filter((item) => item.id !== id));
fetch(`https://api.factarni.tn/article/${id}`, {
method: "DELETE",
headers: {
Authorization:
"Bearer eyJhbGciOiJS...qw2QWltkyA",
},
}).then((response) => response.json());
};
useEffect(() => {
fetch("https://api.factarni.tn/article", {
method: "GET",
headers: {
Authorization:
"Bearer eyJhbGciOiJSUz...WltkyA",
},
})
.then((response) => response.json())
.then((json) => setData(json));
}, []);
const actionColumn = [
{
field: "action",
headerName: "Action",
width: 200,
renderCell: (params) => {
return (
<div className="cellAction">
<Link to="/users/test" style={{ textDecoration: "none" }}>
<div className="viewButton">Modifier</div>
</Link>
<div
className="deleteButton"
onClick={() => handleDelete(params.row.id)}
>
Delete
</div>
</div>
);
},
},
];
return (
<div className="datatable">
<div className="datatableTitle">
Add New Article
<Link to="/users/new" className="link">
<AddBusinessIcon className="icon" /> Add Article
</Link>
</div>
<DataGrid
className="dataGrid"
rows={data}
columns={userColumns.concat(actionColumn)}
pageSize={9}
rowsPerPageOptions={[9]}
checkboxSelection
/>
</div>
);
};
export default Datatable;
Single.jsx:
//...
const Single = ({ inputs, title }) => {
const [data, setData] = useState({
code: "",
article: "",
price: 0,
vat: 0,
status: 0,
company_id: 0,
});
const normalize = (v) => ({
code: v.code,
article: v.article,
price: Number(v.price),
vat: Number(v.vat),
status: Number(v.status),
company_id: Number(v.company_id),
});
function handle(e) {
const newdata = { ...data };
newdata[e.target.id] = e.target.value;
setData(newdata);
console.log(newdata);
}
const handleClick = async (e) => {
e.preventDefault();
const body = normalize(data);
await fetch("https://api.factarni.tn/article/create", {
method: "PUT",
body: JSON.stringify(body),
headers: {
"Content-Type": "application/json",
Authorization:
"Bearer eyJhbGciOiJ...w2QWltkyA",
},
});
};
return (
<div className="New">
<Sidebar />
<div className="newContainer">
<Navbar />
<div className="top">
<h1>{title}</h1>
</div>
<div className="bottom">
<div className="right">
<form>
<div className="formInput"></div>
{inputs.map((input) => (
<div className="formInput" key={input.id}>
<label>{input.label} </label>
<input
type={input.type}
placeholder={input.placeholder}
onChange={(e) => handle(e)}
id={input.label}
name={input.label}
value={input.label}
/>
</div>
))}
<button onClick={handleClick}>Update</button>
</form>
</div>
</div>
</div>
</div>
);
};
export default Single;
In the Database.jsx:
// ... code
<Link to={{ pathname: "/users/test", state: { id: params.row.id }}} style={{ textDecoration: "none" }}>
<div className="viewButton">Modifier</div>
</Link>
// ... code
In the Single.jsx:
import { useLocation } from 'react-router-dom';
// ... later in render function
const { state } = useLocation() // state.id should have your id
Although #deaponn's answer is good, you can also use the useNavigate hook and pass the id, name or any data in the state like below, using programmatic approach rather than Link component exported from react-router library
import { useNavigate } from "react-router-dom";
const navigate = useNavigate();
navigate('/(url on which you want to navigate)', { state: { id:1,name:encryptedId} });
On the navigated component, if you want to retrieve the passed id or name, you can use the useLocation hook as below:
import { useLocation } from "react-router-dom";
const location = useLocation();
var ttid = location.state.id;

Using API to import Chicago Art Institute using react typescript

I am having an extremely hard time trying to import a list of image details on my react application from the Chicago art institute. I struggle a lot understanding API, so a detailed answer would be helpful. As of now, I do understand the code I need for the image list I want, but I am stuck at this code below on making it do what I want with the link provided from the Chicago art documentation. I would like for the API to pop up on the website if possible.
import { Navbar } from '../Navbar';
import Real from '../../assets/images/scream.jpeg'
import { makeStyles } from '#material-ui/core';
const useStyles = makeStyles({
background: {
backgroundImage: `linear-gradient(rgba(0,0,0,0.5) 0%, rgba(0,0,0,0.5) 50%, rgba(0,0,0,0.5) 100%), url(${Real})`,
width: '100%',
height: '100%',
backgroundSize: "cover",
backgroundRepeat: "no-repeat",
backgroundPosition: "center",
position: "absolute",
zIndex: -1,
},
main_text: {
textAlign: 'center',
position: 'relative',
top: '70%',
left: '50%',
transform: 'translate(-50%, -50%)',
color: 'white',
}
})
async function getArt()
{
let response = await fetch(`https://api.artic.edu/api/v1/artworks?ids=208131,240935,142595,120300,13454,151363,102611,191556,117266,137125,126414&fields=id,title,image_id`);
let data = await response.json()
return data;
}
getArt()
.then(data => console.log(data));
export const Art = () => {
const classes = useStyles();
return (
<>
<Navbar />
<div className={`${classes.background}`}>
<div className={classes.main_text}>
<div></div>
</div>
</div>
</>
)
}
Here is a minimalistic implementation. You retrieve data from API, then set your img's src attribute to the API's response.
import React, { useEffect, useState } from "react";
const imageUrl = "https://api.artic.edu/api/v1/artworks?ids=208131,240935,142595,120300,13454,151363,102611,191556,117266,137125,126414&fields=id,title,image_id";
export default function App() {
const [img, setImg] = useState<string | undefined>();
const fetchImage = async () => {
const res = await fetch(imageUrl);
const imageBlob = await res.blob();
const imageObjectURL = URL.createObjectURL(imageBlob);
setImg(imageObjectURL);
};
useEffect(() => {
fetchImage();
}, []);
const classes = useStyles();
return (
<>
<Navbar />
<img src={img} alt="icons" />
<div className={`${classes.background}`}>
<div className={classes.main_text}>
<div></div>
</div>
</div>
</>
);
}
Cheers
You need to use useEffect hook for that inside the component.
Not sure what type of data is returned, I assume that it is an array of objects in this case
interface IArtData {
id: string
//Put whatever type of data it is
}
export const Art = () => {
const classes = useStyles();
const [artData, setArtData] = useState<IArtData[] | undefined | null >() //If it is array, keep like this, else <IArtData | undefined | null>
//Run effect at mount time, fetch data and set state
useEffect(() =>
{
const fetchData = async () => {
let response = await fetch(`https://api.artic.edu/api/v1/artworks?ids=208131,240935,142595,120300,13454,151363,102611,191556,117266,137125,126414&fields=id,title,image_id`);
let data: IArtData[] | undefined | null = await response.json()
//Set data to state
setArtData(data)
}
fetchData()
}, []) //Run only once on mount
return (
<>
<Navbar />
<div className={`${classes.background}`}>
<div className={classes.main_text}>
<div>
{artData?.length
//Check if artData exists and render items
? artData.map((item) => {
console.log(item) //Check what data is inside of item
return (<div><p>{item.something}</p></div>); //Change "something" with a real parameter. For example, if item is {url: "https...", title: "My title"}, change it with item.title
})
: null}
</div>
</div>
</div>
</>
)
}

State is not updating on axios call post Next js

i'm developing an ecommerce whit Nextjs and payments with Paypal.
This is my product component
const Product = () => {
const router = useRouter();
const { id, category } = router.query;
const [product, setProduct] = useState();
const [amount, setAmount] = useState(1);
useEffect(() => {
if (category) {
const foundProduct = products[category].find(
(element) => element.id == id
);
setProduct({ ...foundProduct, amount, total: foundProduct.price * amount });
}
}, [id, amount]);
return (
<>
{!product ? (
<Spinner />
) : (
<div className="product-wrapper">
<div className="product-image">
<Image src={product.image} />
</div>
<div className="product-info">
<h3>{product.title}</h3>
<p className="product-price">
{product.currency} {product.price}
</p>
<p className="product-description">
{product.description}
</p>
<div className="product-cart-container">
<div className="product-cart-handle">
<p onClick={() => amount > 1 && setAmount(amount - 1)}>-</p>
<span>{amount}</span>
<p onClick={() => setAmount(amount + 1)}>+</p>
</div>
<BuyButtton item={product} amount={amount} />
</div>
<div className="product-general">
<p>General information</p>
</div>
</div>
</div>
)}
</>
);
};
and this is my BuyButton component
const BuyButtton = ({ item }) => {
useEffect(() => {
console.log(item);
}, [item]);
return (
<div>
<PayPalScriptProvider
options={{
"client-id":"",
}}
>
<PayPalButtons
createOrder={async () => {
try {
const res = await axios({
url: "http://localhost:3000/api/payment",
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
data: JSON.stringify(item),
});
return res.data.id;
} catch (error) {
console.log(error);
}
}}
onApprove={(data, actions) => {
console.log(data);
actions.order.capture();
}}
style={{ layout: "horizontal", color: "blue" }}
/>
</PayPalScriptProvider>
</div>
);
};
So when i pass this props item to my BuyButton component works fine, the amount and total value updates correctly, the problem is when i do the axios call, it looks like the component stores the initial value of the item prop, so amount and value never changes, its always amount:1, value:item.value. Any ideas? Thanks
I tried storing the item prop in a state but it didin't work as i expected
The solution that solved my problem was adding forceReRender prop to PayPalButtons like this forceReRender={[item]}, so it re-render the button and gets the new amount value
In the Product component, you are passing item & amount to BuyButton
<BuyButtton item={product} amount={amount} />.
You need to add the amount to the BuyButton component as well.
const BuyButtton = ({ item, amount }) => {
and pass the amount in the request body in the axios call
data: JSON.stringify(item),
// need to add the amount data

Issue with API GET response format

I am making a get request to an api and then trying to map over the request. My issue is that the response is changing from data in this usual [{...},{...}] to '[[Object Object][Object Object]]' so that when I try to map over the array, it is throwing an error. I have tried using JSON.stringify() but it does not work. Here is my code:
---- Home.js
import React, { useState, useEffect } from "react";
const Home = () => {
const [tableData, setTableData] = useState([]);
useEffect(() => {
const url =
"https://api.football-data.org/v2/competitions/2021/standings?standingType=HOME";
const fetchItems = async () => {
const apiResult = await fetch(url, {
headers: {
"X-Auth-Token": process.env.REACT_APP_API_KEY,
},
})
.then((res) => res.json())
.catch((err) => console.error(err));
setTableData(apiResult.standings[0].table);
};
fetchItems();
}, []);
return (
<div className="home-container">
<Hero />
<Table data={tableData} />
<Predictions />
<Footer />
</div>
);
};
------ Table.js
import TableList from "./TableList";
const Table = ({ data }) => {
return (
<section className="table" id="table">
<h1 className="table-header">Table</h1>
<div className="table-container">
<TableList data={data} />
</div>
</section>
);
};
--------- TableList.js
import TableCard from "./TableCard";
const TableList = ({ data }) => {
return (
<div className="table-list">
{data.map((index, teamData) => {
return <TableCard key={index} data={teamData} />;
})}
</div>
);
};
If I console log the mapped data, I get '0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20',
instead of the data that I initially receive in the fetch request that is [{position:1, team: {...}, gamesPlayed:9}, {...}].
I have never had this issue before when using a GET request to an API so any and all help is appreciated. Sorry in advance for the poor formatting.

React - How can I wait for the UI to update after multiple api calls?

I am new to react and need some help.
I've created a Pokedex and the app generates data from an API call, but then it needs to do another API call to get more data and then the same process ones more.
In my case the user needs to press the button three times to generate the "complete" information.
Can I need to use the "useEffect" hook that's implemented in React to solve this, if so, how?
Current code:
import Axios from "axios";
import React, { useState } from "react";
function PK() {
const api = Axios.create({
baseURL: "https://pokeapi.co/api/v2/",
});
const [pokemon, setPokemon] = useState({});
const [pokemonDescription, fetchDescription] = useState({});
const [evolution, pokemonEvolution] = useState({});
const searchPokemon = () => {
api.get(`pokemon/magnemite`).then((response) => {
setPokemon({
name: response.data.name,
height: response.data.height,
weight: response.data.weight,
img: response.data.sprites.front_default,
id: response.data.id,
type: response.data.types[0].type.name,
type2: response.data.types[1].type.name,
});
api.get(`pokemon-species/${pokemon.id}/`).then((response) => {
console.log(response.data.evolution_chain);
fetchDescription({
entry: response.data.flavor_text_entries[0].flavor_text,
evolution: response.data.evolution_chain.url,
});
api.get(`${pokemonDescription.evolution}`).then((response) => {
console.log(response.data.chain.evolves_to[0].species.name);
pokemonEvolution({
evolution: response.data.chain.evolves_to[0].species.name,
});
});
});
});
};
return (
<div>
<h1 style={{ textTransform: "capitalize" }}>{pokemon.name}</h1>
<h1>#{pokemon.id}</h1>
<h1>{pokemon.weight / 10} Kg</h1>
<h1>{pokemon.height * 10} Cm</h1>
<img src={pokemon.img} alt="" />
<h1 style={{ textTransform: "capitalize" }}>
Type: {pokemon.type} {pokemon.type2}
</h1>
<h2 style={{ textTransform: "capitalize" }}>
{pokemonDescription.entry}
</h2>
<h1 style={{ textTransform: "capitalize" }}>
Evolution: {evolution.evolution}
</h1>
<button onClick={searchPokemon}>Click me</button>
</div>
);
}
export default PK;
First click:
Second click:
Third click:
So, I don't know how to create a good solution for making the calls simultaneously or to update the UI once all the calls has been made.
Thanks in advance.
const searchPokemon = () => {
api.get(`pokemon/magnemite`).then((response) => {
setPokemon({
name: response.data.name,
height: response.data.height,
weight: response.data.weight,
img: response.data.sprites.front_default,
id: response.data.id,
type: response.data.types[0].type.name,
type2: response.data.types[1].type.name
});
api.get(`pokemon-species/${response.data.id}/`).then((response) => {
fetchDescription({
entry: response.data.flavor_text_entries[0].flavor_text,
evolution: response.data.evolution_chain.url
});
api.get(`${response.data.evolution_chain.url}`).then((response) => {
pokemonEvolution({
evolution: response.data.chain.evolves_to[0].species.name
});
});
});
});
};
Replace your search function with this and it will run just fine.
This is the pattern you are calling your function
api.get().then(res1 => {
setPokemon({...})
api.get(pokemon.id).then(res2 => {
set...
})
})
The problem with your code is that you are assuming that as soon as your setPokemon has ended pokemon will have the value so you are calling it but, that is not how it works. For now just know that the pokemon state will have its value after the function completely executes.
If you want to know further how it works start that from here https://www.youtube.com/watch?v=8aGhZQkoFbQ&t=4s
Now what I did is I took the response which is already present inside that block and passed the id from response.
api.get().then(res1 => {
setPokemon({...}) // res1 is available here
api.get(res1.data.id).then(res2 => {
set... // res2 is available here
})
})
Also there are multiple ways of doing same thing. So keep learning.
I also changed your code for a single state so you dont have to call setState everytime.
const [pokemon, setPokemon] = useState({});
const searchPokemon = async () => {
let data = []
await api.get(`pokemon/magnemite`).then(async (response) => {
data.push({
name: response.data.name,
height: response.data.height,
weight: response.data.weight,
img: response.data.sprites.front_default,
id: response.data.id,
type: response.data.types[0].type.name,
type2: response.data.types[1].type.name
});
await api.get(`pokemon-species/${response.data.id}/`).then(async (response) => {
data.push({
entry: response.data.flavor_text_entries[0].flavor_text,
});
await api
.get(`${response.data.evolution_chain.url}`)
.then((response) => {
data.push({
evolution: response.data.chain.evolves_to[0].species.name
});
});
});
});
data.map((item) => setPokemon(prev => ({...prev, ...item})))
}
return (
<div>
<h1 style={{ textTransform: "capitalize" }}>{pokemon.name}</h1>
<h1>#{pokemon.id}</h1>
<h1>{pokemon.weight / 10} Kg</h1>
<h1>{pokemon.height * 10} Cm</h1>
<img src={pokemon.img} alt="" />
<h1 style={{ textTransform: "capitalize" }}>
Type: {pokemon.type} {pokemon.type2}
</h1>
<h2 style={{ textTransform: "capitalize" }}>
{pokemon.entry}
</h2>
<h1 style={{ textTransform: "capitalize" }}>
Evolution: {pokemon.evolution}
</h1>
<button onClick={searchPokemon}>Click me</button>
</div>
);
If you like the answer please Up Vote. It is just for the sake of Stack Overflow XD. Thanks!!

Resources