I am getting a object from "api" and set it to match but when i try do loop through or render it i get a error.
I have tryed Objct.keys maybe my syntax is wrong im not sure im still learning thx for any help.
const [match, setMatch] = useState();
const [search, setSearch] = useState('');
const [query, setQuery] = useState(4749875544)
useEffect(() => {
getData();
}, [query]);
const getData = async () => {
const response = await
fetch(`https://api.opendota.com/api/matches/${query}`)
const result = await response.json();
setMatch(result);
}
}
return (
<div className="App" >
<form onSubmit={getSearch}
className="search-form">
<input className="search-bar"
type="text"
value={search}
onChange={searchInput}
/>
<Button as="input"
type="submit"
value="Submit" />
</form>
<li>
{
Object.keys(match).map((oneKey,i)=>{
return (
<li key={i}>{match[oneKey]}</li>
)})
}
</li>
</div>
)}
First I would default the state to an Object. It is always good to default your state to the data types you will use. So at the top useState({}).
React can’t render an object. You have to render each key separately. In your map when you return the list item do it with match[oneKey].title or whatever key is actially valid.
Related
I created this React application to practice the fetch API.
However, while writing the code to display the data on the browser via the map method, I got the error message "TypeError: profile.map is not a function". Below is the code:
import React, { Fragment, useEffect, useState } from "react";
import "./App.css";
function App() {
// https://reqres.in/api/users
const [profile, setProfile] = useState([]);
const [loading, setLoading] = useState(false);
const getProfile = async () => {
setLoading(true);
const response = await fetch("https://reqres.in/api/users");
const data = await response.json();
setProfile(data);
setLoading(false);
};
useEffect(() => {
getProfile();
}, []);
return (
<Fragment>
<h1>React fetch</h1>
<div className="main">
<section className="section">
<h2>Get database</h2>
<div>
{loading ? (
<Fragment>loading..</Fragment>
) : (
profile.map(i => {
<Fragment>
<ul>
<li>{i.id}</li>
<li>{i.email}</li>
<li>{i.first_name}</li>
<li>{i.last_name}</li>
<li>
<image src={i.avatar} />
</li>
</ul>
</Fragment>;
})
)}
</div>
</section>
<form className="section">
<h2>Post data</h2>
<input type="text" placeholder="enter detail" />
<button type="submit">Post</button>
</form>
<form className="section">
<h2>Update data</h2>
<select>
<option>Choose data</option>
</select>
<input type="text" placeholder="enter detail" />
<button type="submit">Update</button>
</form>
</div>
</Fragment>
);
}
export default App;
Why isn't map being recognized?
I believe it's because .map is a method for Array prototypes, not for Objects (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)
You can return the array from the object by using data.data instead of just data:
...
const getProfile = async () => {
setLoading(true);
const response = await fetch("https://reqres.in/api/users");
const data = await response.json();
setProfile(data.data); // probably a safer way to do this, but if you console.log(data) you'll see an object is being returned, not an array.
setLoading(false);
};
...
So, const data = await response.json(); After this line is executed the result we are getting inside the data constant is an Object. We can use MAP function only on Array's, not on Objects. And also the Profile data which you are actually searching is inside the "data" key of the data "constant". So while setting profile data, just use setProfile(data.data);.
A suggestions: Use this Chrome Extension for viewing the API data. It indents the json objects automatically
Map needs to return a value.
{loading ? (
<Fragment>loading..</Fragment>
) : (
profile.map(i => {
return (
<Fragment>
<ul>
<li>{i.id}</li>
<li>{i.email}</li>
<li>{i.first_name}</li>
<li>{i.last_name}</li>
<li>
<image src={i.avatar} />
</li>
</ul>
</Fragment>;
)
})
)}
Also, you cannot use the map function on an object. It looks like your response is an object, what you are looking for is the data from the response. Try this...
setProfile(data.data);
I'm trying to display a list of movies title based on the year the user searches for. I dont need to loop all the pages, the results of the first page is enough. I really don't know what am I doing wrong that when I click search the app crashes.
import React, { useState } from "react";
const Movies = () => {
const [search, setSearch] = useState(false);
const [message, setMessage] = useState(null);
const [year, setYear] = useState("");
const [movies, setMovies] = useState([]);
const searchMovies = async (e) => {
e.preventDefault();
setSearch(true);
const url = `https://jsonmock.hackerrank.com/api/movies?Year=${year}`;
try {
const response = await fetch(url);
const data = await response.json();
setMessage(null);
setMovies(data); // needs check
setSearch(false);
} catch (err) {
setMessage("Unexpected Error happened");
setSearch(false);
}
};
return (
<div>
<form action="" onSubmit={searchMovies}>
<input
type="text"
placeholder="Enter a year"
name="year"
value={year}
onChange={(e) => {
setYear(e.target.value);
}}
/>
<button type="submit">Searc</button>
</form>
<div className="movies-container">
{search && !message ? (
<span>Loading...</span>
) : message ? (
<div className="message"> {message} </div>
) : (
movies.map((movie) => <li key={movie.imdbID}> Title: {movie.Title}</li>)
)}
</div>
</div>
);
};
export default Movies;
You need to make sure movies is an array,
Check the value of movies by adding a console log
const data = await response.json();
console.log("data ", data);
setMovies(data);
And i saw the json of your API think you need to put setMovies(data.data); instead of setMovies(data);
I'm making a basic weather app with React, and having an issue getting my setWeather to update weather. I had read that setState doesn't update state the first time it's called, and that seems consistent with the empty object that console.log(weather) returns. cityData returns the full response, as expected, but weather.name and non-nested data (i.e. only strings, not arrays or objects) functions properly, which is unexpected.
I would like to know how to get setWeather to perform as advertised, and why the arrays and objects that the API return are showing as undefined.
import React, { useState } from 'react';
import axios from 'axios';
const Search = () => {
const [query, setQuery] = useState('');
const [weather, setWeather] = useState({});
const findCity = (e) => {
e.preventDefault()
axios.get(`https://api.openweathermap.org/data/2.5/weather?q=${query}&units=imperial&appid=${APIKEY}`)
.then(res => {
const cityData = res.data;
console.log(cityData);
setWeather(res.data);
setQuery('');
console.log(weather)
}).catch(err => console.log(err))
}
return(
<React.Fragment>
<h1>App</h1>
<p>Get the weather in your city!</p>
<form onSubmit={findCity}>
<input
type='text'
className='city-search'
placeholder='What city are you looking for?'
name='city-name'
onChange={e => setQuery(e.target.value)}
value={query}
/>
<button
type='submit'>
Get City
</button>
</form>
<h1>{weather.name}</h1>
</React.Fragment>
)
}
You won't be able to do console.log(weather) in the submit handler because the submit handler is still using the old weather (i.e. from current render). Do this instead:
const Search = () => {
const [query, setQuery] = useState('');
const [weather, setWeather] = useState({});
const findCity = (e) => {
e.preventDefault()
axios.get(`https://api.openweathermap.org/data/2.5/weather?q=${query}&units=imperial&appid=${APIKEY}`)
.then(res => {
const cityData = res.data;
console.log(cityData);
setWeather(res.data);
setQuery('');
}).catch(err => console.log(err))
}
console.log(weather) //<-- THIS IS THE ONLY THING I'VE CHANGED
return(
<React.Fragment>
<h1>App</h1>
<p>Get the weather in your city!</p>
<form onSubmit={findCity}>
<input
type='text'
className='city-search'
placeholder='What city are you looking for?'
name='city-name'
onChange={e => setQuery(e.target.value)}
value={query}
/>
<button
type='submit'>
Get City
</button>
</form>
<h1>{weather.name}</h1>
</React.Fragment>
)
}
https://api.openweathermap.org/data/2.5/weather?q=${query}&units=imperial&appid=${APIKEY}
Are you passing the query and APIKEY here. If not please add them as well to your axios call. Am assuming that your getting an invalid response. APIKEY has to be provided to get a successful response from the Weather API.
I start using Next.js and I am blocked. I'm using the MovieDB API. I wish after having made a search to display in another page the result found (MovieDB doc: search multi). Unfortunately I am blocked because I do not know how to transfer the data and display it on the specific page.
I already managed to display the details of other element using the methods: getInitinialProps and getInitialPath but there I do not see how.
A little clue? ^^
Form page:
import Link from 'next/link';
function SearchForm() {
const [movies, setMovies] = useState([]); //Displays the table of search results
const [search, setSearch] = useState(''); //Value in the research input
const [query, setQuery] = useState('spiderman') //Value to look for when submit
useEffect(() => {
searchMovie()
}, [query])
const searchMovie = async () =>{
const request = await fetch (`https://api.themoviedb.org/3/search/multi?api_key=${myKey}&language=fr&query=${query}`)
const response = await request.json();
setMovies(response.results);
console.log(response.results);
}
const handleChange = (event) =>{
setSearch(event.target.value);
console.log(search);
}
const submitSearchMovie = (event) =>{
event.preventDefault();
setQuery(search)
}
return (
<React.Fragment>
<form className="form" onSubmit={submitSearchMovie}>
<input
className="searchInput"
type="text"
placeholder="Rechercher un film, une série, un artiste"
value={search}
onChange={handleChange}
/>
<Link href='/search/[id]' as={`/search/${search}`}>
<a><input type="submit" value="test link" /></a>
</Link>
</form>
{movies.map((movie,index) =>(
<h4 key={index}>Titre: {movie.title ? movie.title : movie.name}</h4>
))}
</React.Fragment>
);
}
export default SearchForm;```
i'm actually new at react, as a part of my intro a made one web app who picks some recipes from a API, actually everything is ok, but i want to made a message of "No results found" when the item searched return no results, but i don't really know where i made this. Here some of my actually code.
App.js
const App = () => {
const APP_ID = "x";
const APP_KEY = "x";
const [recipes, setRecipes] = useState([]);
const [search, setSearch] = useState("");
const [query, setQuery] = useState('chicken');
useEffect( () => {
getRecipes()
}, [query]);
const getRecipes = async () => {
const response = await fetch(`https://api.edamam.com/search?q=${query}&app_id=${APP_ID}&app_key=${APP_KEY}`
);
const data = await response.json()
setRecipes(data.hits);
console.log(data)
};
const updateSearch = e => {
setSearch(e.target.value)
};
const getSearch = e => {
e.preventDefault();
setQuery(search);
setSearch("");
};
return (
<div className="App">
<form onSubmit={getSearch} className="search-form">
<input
placeholder="Search recipes here"
className="search-bar"
type="text"
value={search}
onChange={updateSearch}
/>
<button
className="search-button"
type="submit">
Buscar
</button>
</form>
<div className="recipes">
{recipes.map(recipe => (
<Recipe
key={recipe.recipe.label}
title={recipe.recipe.label}
calories={recipe.recipe.calories}
image={recipe.recipe.image}
ingridients={recipe.recipe.ingredients}
/>
))}
</div>
</div>
);
};
export default App;
recipe.js
const Recipe = ({title,calories,image,ingridients}) => {
return (
<div className={style.quadrado}>
<h1 className={style.recipe}>{title}</h1>
<ol className={style.list}>
{ingridients.map(ingridient =>(
<li>{ingridient.text}</li>
))}
</ol>
<img className={style.images} src={image} alt=""/>
<p>Calories: {calories}</p>
</div>
);
};
export default Recipe;
i make a connection with the "Edamam" API and get a list of recipes and then render on my web app, but when there's no results i want to put a message saying "Sorry, no results found".
I read some articles here, but i confess that react is kind confuse for me yet.
Thank you for you time!
You could do:
{recipes.lenght === 0 ? (<div>Sorry, no results found</div>)
: recipes.map(recipe => (
<Recipe
key={recipe.recipe.label}
title={recipe.recipe.label}
calories={recipe.recipe.calories}
image={recipe.recipe.image}
ingridients={recipe.recipe.ingredients}
/>
))}
You can check an example about this implementation: https://stackblitz.com/edit/react-typescript-usefetch