I'm slowly learning react and trying to display the results of my searchMap function (movie title/poster) with the TMDB API. I can log the information I need to the console, but I get undefined variables and other errors when trying to display the information in the commented div.
https://codesandbox.io/s/ddmdu4
function App() {
const search = async (event) => {
const searchQuery = event.target.value;
if (searchQuery) {
const searchReq = await fetch(
`https://api.themoviedb.org/3/search/movie?api_key=${process.env.API_KEY}&query=${searchQuery}`
).then((res) => res.json());
const searchResults = searchReq.results;
searchMap(searchResults);
}
};
const searchMap = (searchResults) => {
searchResults.map((movie) => {
console.log(`${movie.title}`);
console.log(`${movie.backdrop_path}`);
});
};
return (
<div className="App">
<div>
<input type="text" onChange={search} placeholder="Search"></input>
</div>
<div>{/* Display movie title/poster*/}</div>
</div>
);
}
export default App;
Since you want to update the DOM each time the result changes I would recommend using that inside of a state like so:
const [searchResults, setSearchResults] = React.useState([]);
In your async search function update the state by using its appropiate "setter":
.then((res) => res.json());
setSearchResults(searchReq.results);
And inside your return you can map the result as follows:
<div>
{searchResults.map((movie) => (
<>
<div>{movie.title}</div>
<div>{movie.backdrop_path}</div>
</>
))}
</div>
Related
I would like to be able to make both data.account and data.assets accessbile individually. The idea is to be able to insert this component into a page where I can say something like:
import UserAccounts from '...';
"This user (**data.account**) owns this number (**data.assets**) of assets".
The following is the component code:
function UserAccounts() {
const [accounts, setAccounts] = useState();
useEffect(() => {
async function fetchData() {
const res = await fetch(
'https://proton.api.atomicassets.io/atomicassets/v1/accounts?limit=10'
);
const { data } = await res.json();
setAccounts(data);
}
fetchData();
}, []);
if (!accounts) {
return (
<div>
<Spinner />
</div>
);
}
const account = accounts.map((data) => {
return <>{(data.account, data.assets)}</>;
});
return <></>;
}
export default UserAccounts;
the way that it is now, it's pulling the accounts from the api. The problem is that it's not set to return anything. I'm trying to figure out how I can decide which to return based on what I need (data.account or data.assets
I'm new to ReactJS and I'm now trying to do an interactive comments section (taken from frontendmentor.io), but the App component just doesn't show what it's supposed to show
This is my App component:
function App() {
const [data, setData] = useState([]);
useEffect(() => {
const getComm = async () => {
await fetchData();
};
getComm();
}, []);
console.log(data);
const fetchData = async () => {
const res = await fetch("db.json").then(async function (response) {
const comm = await response.json();
setData(comm);
return comm;
});
};
return (
<Fragment>
{data.length > 0 ? <Comments data={data} /> : "No Comments to Show"}
</Fragment>
);
}
export default App;
The console.log(data) logs two times:
the first time it's an empty Array;
the second time it's the Array with my datas inside.
As it follows:
If I force the App to print the Comments it just says that cannot map through an undefined variable
This is my Comments component:
function Comments({ data }) {
return (
<div>
{data.map((c) => (
<Comment key={c.id} />
))}
</div>
);
}
export default Comments;
I'm wondering why the page still displays No Comments to Show even if the log is correct
#Cristian-Irimiea Have right about response get from fetch. Response is an a object and can't be iterate. You need to store in state the comments from response
But you have multiple errors:
Take a look how use async function. Your function fetchData looks bad.
// Your function
const fetchData = async () => {
const res = await fetch("db.json").then(async function (response) {
const comm = await response.json();
setData(comm);
return comm;
});
};
// How can refactor
// fetchData function have responsibility to only fetch data and return a json
const fetchData = async () => {
const response = await fetch("./db.json");
const body = await response.json();
return body;
};
You are updating state inside fetch function but a good solution is update state then promise resolve:
useEffect(() => {
// here we use .then to get promise response and update state
fetchData().then((response) => setData(response.comments));
}, []);
The initial state of your data is an array.
After you fetch your data from the response you get an object. Changing state types is not a good practice. You should keep your data state as an array or as an object.
Considering you will keep it as an array, you need use an array inside of setData.
Ex.
comm && Array.isArray(comm.comments) && setData(comm.comments);
As for your Comments component you should consider expecting an array not an object.
Ex.
function Comments(data) {
return (
<div>
{data.map((c) => (
<Comment key={c.id} />
))}
</div>
);
}
export default Comments;
I'm parsing data from the NASA API using React, and for some reason I can map one nested object within the return but not the other.
Here is my parent component:
import React, { useState } from 'react'
import './NasaAPI.scss'
import NasaImages from './NasaImages'
const NasaAPI = () => {
const [nasaData, setNasaData] = useState([])
const [nasaImage, setNasaImage] = useState("")
const [searchInput, setSearchInput] = useState("")
const [loading, setLoading] = useState(true)
const fetchData = async (e) => {
const data = await fetch(`https://images-api.nasa.gov/search?q=${searchInput}`)
.then(response => response.json())
.then(data => setNasaData(data.collection.items))
.catch(err => console.log(err))
.finally(setLoading(false))
}
const handleSubmit = (e) => {
e.preventDefault()
fetchData()
}
const handleChange = (e) => {
setSearchInput(e.target.value)
}
return (
<div>
<h2>Search NASA Images</h2>
<form onSubmit={handleSubmit}>
<input name="searchValue" type="text" value={searchInput} onChange={handleChange}></input>
<button value="Submit">Submit</button>
</form>
<section>
<NasaImages nasaData={nasaData} loading={loading}/>
</section>
</div>
)
}
export default NasaAPI
Here's where the issue is, in the child component:
import React from 'react'
const NasaImages = ({ nasaData }) => {
console.log(nasaData)
return (
<div>
<h2>This is a where the data go. 👇</h2>
{
nasaData && nasaData.map((data, idx) => {
return (
<div key={idx}>
<p>{data.href}</p>
<div>
{/* {data.links.map((data) => {
return <p>{data.href}</p>
})} */}
{data.data.map((data) => {
return <p>{data.description}</p>
})}
</div>
</div>
)
})
}
</div>
)
}
export default NasaImages
The current configuration works, and will display a data.description (data.data.map) mapping property. However, I want the commented code immediately above it to work which displays a data.href (data.links.map) property.
The JSON looks as follows:
So, the issue is that I can map one set of properties, data.data.map, but cannot access the other in the same object, data.links.map, without getting the error "TypeError: Cannot read property 'map' of undefined". Thank you in advance!
There exists a data element sans a links property, in other words there is some undefined data.links property and you can't map that. Use Optional Chaining operator on data.links when mapping, i.e. data.links?.map. Use this on any potentially undefined nested properties.
const NasaImages = ({ nasaData = [] }) => {
return (
<div>
<h2>This is a where the data go. 👇</h2>
{nasaData.map((data, idx) => (
<div key={idx}>
<p>{data.href}</p>
<div>
{data.links?.map((data, i) => <p key={i}>{data.href}</p>)}
{data.data?.map((data, i) => <p key={i}>{data.description}</p>)}
</div>
</div>
))}
</div>
)
}
so when i do my login and i try to redirect to this page it appears me that error it must be something with useEffect i dont know
here is my code
useEffect(() => {
let canUpdate = true;
getVets().then((result) => canUpdate && setVets(result));
return function cleanup() {
canUpdate = false;
};
}, []);
const getVets = async () => {
const url = 'http://localhost:8080/all/vet';
const response = await fetch(url);
const data = await response.json();
setVets(data);
};
// const { appointmentType, animalID, room, hora, notes } = this.state;
return (
<React.Fragment>
<div class='title'>
<h5>2 médicos vetenários disponÃveis</h5>
</div>
<div>
{vets.map((data) => (
<ObterMedicos
key={data.name}
name={data.name}
specialty={data.specialty}
/>
))}
</div>
</React.Fragment>
);
}
vets might not have data on the first render and when the code tries to execute map operation on it, it gets undefined.map, which is not allowed.
You can either set vets to empty array at the time of defining the state
const [vets,setVets] = useState([]);
or just check on vets using Optional chaning (?) before using the map function:
{vets?.map((data) => (
<ObterMedicos
key={data.name}
name={data.name}
specialty={data.specialty}
/>
))}
I am trying to use react-query with nextjs to prefetch query on server. It works for the initial query which gets a list of items. However when I try to fetch each item inside component it only fetches it on the client side.
export default function Home() {
const { data } = useQuery("pokemons", fetchPokemons);
return (
<>
<div>
{data.map((pokemon) => (
<Pokemon key={pokemon.name} pokemon={pokemon}/>
))}
</div>
</>
);
}
export async function getStaticProps() {
const queryClient = new QueryClient()
await queryClient.prefetchQuery('pokemons', fetchPokemons)
const fetchedPokemons = queryClient.getQueryData()
//query each pokemon
fetchedPokemons.forEach(async (pokemon) => {
await queryClient.prefetchQuery(pokemon.name, () => fetchPokemon(pokemon.url))
});
return {
props: {
dehydratedState: dehydrate(queryClient),
},
}
}
And here is code for the component which also queries each item.
const Pokemon = ({pokemon}) => {
const {data} = useQuery(pokemon.name, () => fetchPokemon(pokemon.url))
// logs only in browser, on server it is undefined
{console.log(data)}
return (
<div>
<h3>
Name - {data.name}
</h3>
<h4>Base XP - {data.base_experience}</h4>
</div>
)
}
Can you please tell me what am I doing wrong that the query doesn't execute on server or is it an issue of the library itself?
when you use getQueryData to get data from the cache, you need to provide the key of the data you want to get:
await queryClient.prefetchQuery('pokemons', fetchPokemons)
const fetchedPokemons = queryClient.getQueryData('pokemons')
alternatively, you can use fetchQuery to also retrieve the data immediately
try {
const fetchedPokemons = await queryClient.fetchQuery('pokemons')
} catch (error) {
// handle error
}
Be aware that fetchQuery throws errors (as opposed to prefetchQuery, which does not), so you might want to handle errors somehow.
I was able to solve this by combining two of my fetching functions into one like so
const fetchPokemons = async () => {
const { data } = await axios.get(
"https://pokeapi.co/api/v2/pokemon?limit=10&offset=0"
);
const pokemonArray = await Promise.all(
data.results.map(async (pokemon) => {
const res = await axios.get(pokemon.url);
return res.data;
})
);
return pokemonArray;
};
export default function Home() {
const { data } = useQuery("pokemons", fetchPokemons);
return (
<>
<div>
{data.map((pokemon) => (
<Pokemon key={pokemon.name} pokemon={pokemon}/>
))}
</div>
</>
);
}
export async function getStaticProps() {
const queryClient = new QueryClient();
await queryClient.prefetchQuery("pokemons", fetchPokemons);
return {
props: {
dehydratedState: dehydrate(queryClient),
},
};
}