How to get data using async await? - javascript

How to get the data correctly
import { NextApiHandler } from "next";
import data from "../../../lib/data.json";
const cars: NextApiHandler = (_req, res) => {
res.status(200).json(data);
};
export default cars;
I tried to use async await for getting data but something went wrong. When I`m trying to print in console.log what is "cars" it returns me function instead of promise.

You can try this way to get data
import React, { useEffect, useState } from 'react';
import Item from '../Item/Item';
const Items = () => {
const [items, setItems] = useState([]);
useEffect( ()=>{
fetch('http://localhost:5000/items')
.then(res => res.json())
.then(data => setItems(data));
}, [])
return (
<div id='items' className='container'>
<h1 className='item-title'>Items For You</h1>
<div className="items-container">
{
items.map(item => <Item
key={item._id}
item={item}
>
</Item>)
}
</div>
</div>
);
};
export default Items;

Related

Why can't I render multiple cards using map?

I'm trying to render multiple cards by pulling data from the API. But the return is an array, I don't understand why the map is not working.
const CharacterCard = () => {
const [showModal, setShowModal] = useState(false)
const openModal = () => {
setShowModal(prev => !prev)
}
const characters = useRequestData([], `${BASE_URL}/characters`)
const renderCard = characters.map((character) => {
return (
<CardContainer key={character._id} imageUrl={character.imageUrl}/>
)
})
return (
<Container>
{renderCard}
<ModalScreen showModal={showModal} setShowModal={setShowModal} />
</Container>
)
}
export default CharacterCard
The hook is this
import { useEffect, useState } from "react"
import axios from "axios"
const useRequestData = (initialState, url) => {
const [data, setData] = useState(initialState)
useEffect(() => {
axios.get(url)
.then((res) => {
setData(res.data)
})
.catch((err) => {
console.log(err.data)
})
}, [url])
return (data)
}
export default useRequestData
console error image
requisition return image
API: https://disneyapi.dev/docs
Looks like the default value of the characters is undefined.
So something like (characters || []).map.. will help I think.
For deeper look at this you can debug useRequestData hook, as I can't see the source of that hook from you example

How to pass data from child to parent and render content based on selected value in dropdown?

I am learning React as I am fetching data from Pokéapi to make a list component, card component, detail component and filter component. I am trying to make a filter so you can filter by pokémon type. Only the cards that also contain that type string should then render (Not there yet). So I am not sure if a) I should make a different call from API inside PokemonList depending on selected value or b) if I should compare the values and just change how the PokemonCard element is rendered inside PokemonList.js depending on the comparison. I managed to pass data from filter to the list component. I have then been trying to pass the type data from PokemonCard.js to the list component so that I can compare these two values but I find it hard to use callbacks to pass the type data from the card component, since I dont pass it through an event or something like that.
Which method should I use here to simplify the filtering? Make different API call or render PokemonCard element conditionally?
Is it a good idea to compare filter option to pokemon card's type in PokemonList.js? Then how can I pass that data from the card component since I don't pass it through click event?
Thankful for any ideas! I paste the code from list component that contains the cards, card component and filter component.
PokemonList component:
import { useState } from 'react';
import useSWR from 'swr';
import PokemonCard from './PokemonCard';
import PokemonFilter from './PokemonFilter';
import './PokemonList.css';
const PokemonList = () => {
const [index, setIndex] = useState(0);
const [type, setType] = useState('');
function selectedType(type) { // value from filter dropdown
setType(type)
console.log("handled")
console.log(type)
}
const url = `https://pokeapi.co/api/v2/pokemon?limit=9&offset=${index}`;
const fetcher = (...args) => fetch(...args).then((res) => res.json())
const { data: result, error } = useSWR(url, fetcher);
if (error) return <div>failed to load</div>
if (!result) return <div>loading...</div>
result.results.sort((a, b) => a.name < b.name ? -1 : 1);
return (
<section>
<PokemonFilter onSelectedType={selectedType} selectedPokemonType={type} />
<div className="pokemon-list">
<div className="pokemons">
{result.results.map((pokemon) => (
<PokemonCard key={pokemon.name} pokemon={pokemon} /> // callback needed??
))}
</div>
<div className="pagination">
<button
onClick={() => setIndex(index - 9)}
disabled={result.previous === null}
>
Previous
</button>
<button
onClick={() => setIndex(index + 9)}
disabled={result.next === null}
>
Next
</button>
</div>
</div>
</section>
)
}
export default PokemonList;
PokemonCard component:
import { Link } from "react-router-dom";
import useSWR from 'swr';
import './PokemonCard.css';
const PokemonCard = ({ pokemon }) => {
const { name } = pokemon;
const url = `https://pokeapi.co/api/v2/pokemon/${name}`;
const { data, error } = useSWR(url);
if (error) return <div>failed to load</div>
if (!data) return <div>loading...</div>
const { types, abilities } = data;
// types[0].type.name <---- value I want to pass to PokemonList.js
return (
<div className='pokemon-card'>
<div className='pokemon-card__content'>
<img
className='pokemon-card__image'
src={data.sprites.front_default}
alt={name}
/>
<div className='pokemon-card__info'>
<p className='pokemon-card__name'>Name: {name}</p>
<p className='pokemon-card__abilities'>Abilities: {abilities[0].ability.name}</p>
<p className='pokemon-card__categories'>Category: {types[0].type.name}</p>
</div>
</div>
<Link className='pokemon-card__link' to={{
pathname: `/${name}`,
state: data
}}>
View Details
</Link>
</div>
)
}
export default PokemonCard;
PokemonFilter component:
import './PokemonFilter.css';
import useSWR from 'swr';
const PokemonFilter = ({onSelectedType, selectedPokemonType}) => {
const url = `https://pokeapi.co/api/v2/type/`;
const fetcher = (...args) => fetch(...args).then((res) => res.json())
const { data: result, error } = useSWR(url, fetcher);
if (error) return <div>failed to load</div>
if (!result) return <div>loading...</div>
function filteredTypeHandler(e) {
console.log(e.target.value);
onSelectedType(e.target.value);
}
console.log(selectedPokemonType)
return(
<div className="pokemon-types__sidebar">
<h2>Filter Pokémon by type</h2>
<select
name="pokemon-type"
className="pokemon-types__filter"
onChange={filteredTypeHandler}
>
<option value="All">Filter By Type</option>
{result.results.map((type) => {
return (
<option key={type.name} value={type.name}> {type.name}</option>
)
})}
</select>
</div>
)
}
export default PokemonFilter;
Here is an example to improve, modify, ... I didn't test, it's just a visual example.
I don't know about useSWR sorry, I use axios in my example...
If you want to centralize all your API requests, you can create a useApi hook, on the internet you will find tutorials.
PokemonList.js
import React, { useState, useEffect } from 'react';
import axios from 'axios'; // or swr
import PokemonFilter from './PokemonFilter';
import PokemonCard from './PokemonCard';
export default function PokemonList() {
const [data, setData] = useState([]);
const [filter, setFilter] = useState('');
// Executed every first render
useEffect(() => {
getData();
}, []);
// Executed only when filter changes
useEffect(() => {
getDataByTypes(filter);
}, [filter]);
// Get data
const getData = async () => {
const uri = 'https://xxx';
try {
const response = await axios.get(uri);
setData(response.data...);
} catch (error) {
console.log(error);
}
};
// Get data by types
const getDataByTypes = async (filter) => {
const uri = `https://xxx/type/${filter}...`;
if (filter) {
try {
const response = await axios.get(uri);
setData(response.data...);
} catch (error) {
console.log(error);
}
}
};
return (
<div className="main">
<PokemonFilter filter={filter} setFilter={setFilter} />
<div className="container">
<div className="cards-container">
{data.map((d) => (
<PokemonCard key={d.name} data={d} />
))}
</div>
</div>
</div>
);
}
PokemonCard.js
import React, { useState, useEffect } from 'react';
import axios from 'axios';
export default function PokemonCard({ data }) {
const [pokemons, setPokemons] = useState();
useEffect(() => {
getPokemons(data);
}, [data]);
// Get Pokemons
const getPokemons = async (data) => {
const uri = `https://xxx/pokemon/${data.name}/`;
try {
const response = await axios.get(uri);
setPokemons(response.data...);
} catch (error) {
console.log(error);
}
};
return (
<div>
{pokemons && (
<div className="card">
<img src={pokemons.sprites.front_default} alt={pokemons.name} />
<p>{pokemons.name}</p>
<p>{pokemons.abilities[0].ability.name}</p>
<p>{pokemons.types[0].type.name}</p>
</div>
)}
</div>
);
}
PokemonFilter.js
import React, { useState, useEffect } from 'react';
import axios from 'axios';
export default function PokemonFilter({ filter, setFilter }) {
const [types, setTypes] = useState([]);
useEffect(() => {
getType();
}, []);
// Get Type
const getType = async () => {
const uri = 'https://xxx/type/';
try {
const response = await axios.get(uri);
setTypes(response.data.results....);
} catch (error) {
console.log(error);
}
};
const handleFilter = (e) => {
setFilter(e.target.value);
};
return (
<select onChange={handleFilter} value={filter}>
<option>Filter by type</option>
{types.map((type) => {
return (
<option key={type.name} value={type.name}>
{type.name}
</option>
);
})}
</select>
);
}

Cannot display Fetched data to the UI in React

it doesn't show an error and the project works just fine. I can log the data to the console as well. but it doesn't display in the UI. this is a tutorial project on youtube
I'm getting data from the API and passing that to the tours and tour components. and Tour component displays the fetched data.
App component
import React, { useState, useEffect } from "react";
import Loading from "./Loading";
import Tours from "./Tours";
// ATTENTION!!!!!!!!!!
// I SWITCHED TO PERMANENT DOMAIN
const url = "https://course-api.com/react-tours-project";
function App() {
const [loading, setLoading] = useState(true);
const [tours, setTours] = useState([]);
const fetchTours = async () => {
try {
const response = await fetch(url);
const tours = await response.json();
setLoading(false);
setTours(tours);
} catch (error) {
setLoading(true);
console.log(error);
}
};
useEffect(() => {
fetchTours();
}, []);
if (loading) {
return (
<main>
<Loading />
</main>
);
}
return (
<main>
<Tours tours={tours} />
</main>
);
}
export default App;
Tours component
import React from "react";
import Tour from "./Tour";
const Tours = ({ tours }) => {
return (
<section>
<div className="title">
<h2>Our Tours</h2>
<div className="underline"></div>
</div>
<div>
{tours.map((tour, index) => {
return <Tour key={tour.id} {...tours} />;
})}
</div>
</section>
);
};
export default Tours;
Tour Component
import React, { useState } from "react";
const Tour = ({ id, image, info, price, name }) => {
return (
<article className="single-tour">
<img src={image} alt={name} />
<footer>
<div className="tour-info">
<h4>{name}</h4>
<h4 className="tour-price">AUD{price}</h4>
</div>
<p>{info}</p>
<button className="delete-btn">Not Interested</button>
</footer>
</article>
);
};
export default Tour;
Try this code:
useEffect(async () => {
await fetchTours();
}, []);
I think your UI has not updated after the data arrived. You need to wait for your data is fetched.
Try to remove the setting of state in the function and move it to use effect. Have the API call only return the list instead of having it retrieving the list and setting the state.
const fetchTours = async () => {
const response = await fetch(url);
const tours = await response.json();
return tours;
};
useEffect(() => {
const fetchAndSetTourState = async () => {
const data = await fetchTours();
setTours(data);
setLoading(false);
}
fetchAndSetTourState();
}}, []);

fetching random json getting first undefined then result

Beginner on reactjs here, trying to fetch random json, getting the result i want to get, but not the way i want it, for some reason it prints first 'undefined' then after that the result. Why cant i get just the result and without this '?'
my code:
import { useEffect, useState } from "react";
import "./App.css";
function App() {
const [thumbnail, setThumbnail] = useState([]);
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/photos")
.then((response) => response.json())
.then((json) => {
setThumbnail(json);
});
}, []);
console.log(thumbnail[0]?.thumbnailUrl);
return (
<div className="App">
<h1>Build</h1>
<p></p>
</div>
);
}
export default App;
console.log() inside App() directly will use the initial state of. thumbnail which is the empty, so it will show undefined.
To check the thumbnail, you should use another useEffect with adding a thumbnail dependency.
useEffect(() => {
if (thumbnail.length > 0) {
console.log(thumbnail[0].thumbnailUrl);
}
}, [thumbnail]);
import { useEffect, useState } from "react";
import "./App.css";
function App() {
const [thumbnail, setThumbnail] = useState([]);
const [isLoaded, setLoaded] = useState(false);
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/photos")
.then((response) => response.json())
.then((json) => {
setLoaded(true);
setThumbnail(json);
});
}, []);
useEffect(() => {
if (isLoaded) {
console.log(thumbnail[0]?.thumbnailUrl);
}
}, [thumbnail]);
return (
<div className="App">
<h1>Build</h1>
<p></p>
</div>
);
}
export default App;
While the response of your http does not come, you can simply render a loading component (a text in this example), then when thumbnail state changes, React will re-render your component and update it with the new data.
Just a working example:
import React, { useEffect, useState } from "react";
import "./App.css";
function App() {
const [thumbnail, setThumbnail] = useState([]);
const [isLoading, setIsLoading] = useState(false);
useEffect(() => {
setIsLoading(true);
fetch("https://jsonplaceholder.typicode.com/photos")
.then((response) => response.json())
.then((json) => {
setThumbnail(json);
})
.finally(() => {
setIsLoading(false);
});
}, []);
return (
<div className="App">
<h1>Build</h1>
{isLoading ? (
<h3>Loading...</h3>
) : (
thumbnail.map((item) => {
return <span key={item.id}>{item.title}</span>;
})
)}
</div>
);
}
export default App;

How can i passing id which match?

I'm new to ReactJS, please don't judge me.
So I fetch some user and I want to display them one by one, but as you can see in this picture I don't get the ID, but I get the id in the iteration
import React, { useState, useEffect } from 'react';
import '../App.css';
import { Link } from 'react-router-dom';
function Users() {
useEffect(() => {
fetchItems();
}, []);
const [items, setItems] = useState([]);
const fetchItems = async () => {
const data = await fetch('https://jsonplaceholder.typicode.com/users');
const items = await data.json();
console.log(items.id);
setItems(items);
};
return (
<div>
{items.map(item => (
<h1 key={item.id}>
<Link to={`/users/${item.id}`}>{item.name}</Link>
</h1>
))}
</div>
);
}
export default Users;
and here is my UserDetails :
import React, { useState, useEffect } from 'react';
import '../App.css';
function UserDetail({ match }) {
useEffect(() => {
fetchItem();
console.log(match.id);
}, [match]);
const [user, userItem] = useState({});
const fetchItem = async () => {
const data = await fetch(
`https://jsonplaceholder.typicode.com/users/${match.id}`
);
const user = await data.json();
console.log(user);
};
return (
<div>
<h1>Item</h1>
</div>
);
}
export default UserDetail;
and i get this error.
I dont' get my id,and i don't know why.

Categories

Resources