I am getting an error on my .map function. I believe the issue is greater than that though because sometimes my fetch comes back as undefined. I have been looking into solutions but haven't found anything that has given me a solution.
Props - is a logged-in user object that has the users ID
discBag consoles as an array sometimes but also will console as undefined. This is where I believe my issue is happening. I have looked into component mounting, but I was confused with the class and super() syntax.
here is the error I am getting along with the two console.logs
I am new to web development and this is my very first stack overflow question. Any solutions or guidance to the solution is greatly appreciated!
function DiscBag(props) {
const [loading, setLoading] = useState(true);
const [discBag, setDiscBag] = useState([]);
const userID = props.user.user.id;
console.log(userID)
console.log(discBag)
const getDiscs = async () => {
try {
const response = await fetch(`/users/${userID}`)
const data = await response.json()
setLoading(false)
setDiscBag(data.discBag)
} catch (error) {
console.log(error)
}
};
useEffect(() => {
getDiscs();
}, []);
if (loading) {
return <div> ....loading bro</div>;
}
return (
<div className="child">
<p>not loading</p>
{discBag.map((index, discs) => (
<div className="discs" key={index}>
{discs}
</div>
))}
</div>
);
}
According to your description, it seems that there are times that the call to your server does not return a data.discBag value, which causes the discBag state to be empty (and the map function can only run on arrays, here is the fix for the problem:
{discBag?.map((discs, index) => (
Can you try with {discBag.map((discs, index) => ... ? first one is element, second one is the index like below;
array.map((currentElement, index) => { something... })
Related
Hi I am trying to map an array of an api to display paragraphs for every index within the array. However I keep getting an error :
**> TypeError: undefined is not an object (evaluating
'post.game_indices.version.name')**
But when I console log post and use my buttons below it displays what I want and not undefined. So why is it undefined when I want to map the paragraphs?
'''
import React, {useEffect,useState} from 'react'
import instance from './axios'
const Home = () => {
const [post, setPost] = useState(null);
const [error,setError] = useState(null);
const [showTypes,setShowTypes]=useState(false);
const [showAbilities,setShowAbilities]=useState(false);
useEffect(() => {
instance.get("bulbasaur/").then((response) => {
setPost(response.data);
}).catch(error => {
setError(error);
})
},[]);
console.log(post);
if (error) return `Error: ${error.message}`;
if (!post) return 'no post!'
return (
<>
<h1>{post.name}</h1>
<button onClick={()=>setShowTypes(!showTypes)}>types</button>
{showTypes? <p>{(post.types[0].type.name)}</p>:null}
{showTypes? <p>{(post.types[1].type.name)}</p>:null}
<button onClick={()=>setShowAbilities(!showAbilities)}>abilities</button>
{showAbilities? <p>{(post.abilities[0].ability.name)}</p>:null}
{showAbilities? <p>{(post.abilities[1].ability.name)}</p>:null}
{/* <button onClick={gameVersion}>game versions</button> */}
{post.game_indices.version.name.map(name => <p key={post.game_indices.version.name}>{name}</p>)}
</>
)
}
export default Home;
'''
ok, I recreated your app and found a problem - you should map on array post.game_indices and then display index.version.name
{post.game_indices.map((index, idx) => <p key={idx}>{index.version.name}</p>)}
The error comes from the fact that you version is not an object in game_indices (it is undefined, which means maybe game_indices is an empty object or it does not contain the version key). Can you please check your post object again ?
I created a home page that contains three components HomeHeader, CompanyList and ScrollToTopBtn.
Focusing on CompanyList it is a container component that shows list of CompanyCards that were fetched using an API in Home page. List of companies are initialized in Home page like this
const [companies, setCompanies] = useState([]);
The problem is that initially after making the API call, I use spread operator to update the companies list like this
const fetchedCompanies = await fetchFeedData(page);
console.log(fetchedCompanies);
setCompanies((prevCompanies=>{return [...prevCompanies,fetchedCompanies]}));
console.log(companies);
But an error occurs Uncaught TypeError: prevCompanies is not iterable since I believe that companies list is initially empty.
I tried to use another approach by using concat method but companies list stayed empty and showed no companies found message.
Below is the source code for Home page
const Home = () => {
const [page, setPage] = useState(1); //In order to avoid showing "no companies found" initially
const [isLoading, setIsLoading] = useState(true);
const [companies, setCompanies] = useState([]);
const [isError, setIsError] = useState(false);
const [hasMore, setHasMore] = useState(false);
useEffect(() => {
const fetchData = async () => {
setIsLoading(true);
setIsError(false);
try {
const fetchedCompanies = await fetchFeedData(page);
setCompanies((prevCompanies=>{prevCompanies.concat(fetchedCompanies)})); //problem here
setHasMore(fetchedCompanies.length > 0)
} catch (e) {
setIsError(true)
setHasMore(false);
}
setIsLoading(false)
}
fetchData();
}, [page])
return (
<div>
<ScrollToTopBtn />
<Helmet>
<title>{stackinfo.title} - {home.title}</title>
</Helmet>
<HomeHeader />
{
isLoading ? (<LoadingSpinner />) :
isError ? (<ErrorBoundary message={somethingWrongError.message}></ErrorBoundary>) :
<CompanyList companies={companies} ></CompanyList>
}
<Container className={"mt-5"}>
<Row>
<Col sm={12}>
{(!isLoading && !isError && hasMore) &&
<CustomBtn
ButtonText={showMoreBtnText.message}
onClick={() => { console.log("Need to increment number of pages") }}
></CustomBtn>}
</Col>
</Row>
</Container>
</div>
)
}
I tried to check the fetchedCompanies and companies after making the API call
const fetchedCompanies = await fetchFeedData(page);
//Returning new array containing previous companies and recent fetchedCompanies
console.log(fetchedCompanies);
setCompanies((prevCompanies=>{prevCompanies.concat(fetchedCompanies)}));
console.log(companies);
fetchedCompanies logged an array that has 9 elements, while companies as mentioned above logged empty array [].
Sorry if I missed something, I am still new to React.
You can do this below to update
setCompanies([...companies, ...fetchedCompanies])
If fetched Company are totally new Array containing all with previous record then just do it below;
setCompanies([...fetchedCompanies]);
//OR
setCompanies(fetchedCompanies);
If you have empty strings then do this below
setCompanies([...companies, ...fetchedCompanies.filter(com => !com)]);
This is trying to mutate state, not return a new state (or maybe you just forgot the return keyword?):
setCompanies((prevCompanies=>{prevCompanies.concat(fetchedCompanies)}));
Your previous attempt was closer:
setCompanies(prevCompanies=>{return [...prevCompanies, fetchedCompanies]});
But if fetchedCompanies is also an array as the name implies then you forgot its spread operator:
setCompanies(prevCompanies=>{return [...prevCompanies, ...fetchedCompanies]});
Without that the resulting array would be weird at best.
You can also simplify a little:
setCompanies(prevCompanies=>[...prevCompanies, ...fetchedCompanies]);
And if you don't expect these calls to overlap at all, you could potentially simplify a lot:
setCompanies([...companies, ...fetchedCompanies]);
If after that there is still an empty string then it seems that the data has an empty string. In that case you'd have to filter that out manually, and where you do that is really up to you if the act of filtering might mess with the rest of the logic you have there (the hasMore value, for example). But you can append .filter() to the resulting array any time you like. When fetching, when updating state, or even just when rendering.
You would be better to look where the empty string is coming from and try to resolve that issue but if you simple want to remove the empty string, use the following.
prevCompanies.concat(fetchedCompanies).filter(Boolean)
I'm learning to use firebase and react. I have shared my firestore collection image. and my code for fetching the array from my document is given below.
This code is fetching the data from my firestore database and then storing the result in my watchlistMovies react state. when i try to log the react state or even data.data() it gives the desired result but when i try to map over the array or do something similar like logging watchlistMovies.myList[0].media_type it hits me with an error. i tried my best trying different things making it work but it breaks a thing or two in process.
I hope someone here will help me. Thank you in advance! : )
updated the code
const Watchlist = () => {
const [watchlistMovies, setwatchlistMovies] = useState([]);
const {currentUser} = useAuth()
const usersCollectionRef = collection(db,"users")
const docRef = doc(db,"users",currentUser.uid)
useEffect(() => {
const getWatchListMovies = async () => {
const data = await getDoc(docRef)
if (data.exists()) {
console.log(data.data());
setwatchlistMovies([...watchlistMovies ,data.data().myList])
} else {
console.log("empty");
}
}
getWatchListMovies();
}, [])
console.log(watchlistMovies);
// console.log(watchlistMovies.myList[0]);
return (
<div className="content-page-area">
<h1 className="trending-text"> My Watchlist </h1>
<Container className="watchlist-container">
<hr/>
{watchlistMovies.map(
(item) => (
<ListContent
item_poster={item.poster_url}
item_title={item.media_title}
item_year={item.release_year}
item_rating={item.media_rating}
item_type={item.media_type}
item_id={item.media_id}
/>
)
)}
</Container>
<br/>
<br/>
<br/>
</div>
)
}
export default Watchlist
I'm making a blog with react, next.js, and json-server. I have come as far as dynamically loading blog posts and other UI, but now when I'm trying to load the comments dynamically as well, it's not working.
The component in question is this one.
const Comments = ({ id }) => {
const [com, setCom] = useState([]);
useEffect(() => {
const getComments = async () => {
const comment = await fetchPost(id);
if (comment["comments"].length == 0) return;
const comments = [...comment["comments"]];
setCom([...comment["comments"]]);
};
getComments();
}, []);
return (
<div>
{com.map((p) => {
console.log(p.comment);
<Comment key={p.id} comment={p.comment} />;
})}
</div>
);
};
I know that the component is getting called and have the information as I'm logging it to console inside map. What I can't get my head around is why it is not rendering as it is a near carbon copy of how I render the blog-posts.
Aside from the above, I have tried the following:
checked syntax
Running <Comment/> with and without a key
putting in strings directly inside the component com.map, instead of p.comment == does not render
lifting state and useEffect up to <Post/>
Your function is not returning anything so React has nothing to render
{com.map((p) => (
<Comment key={p.id} comment={p.comment} />;
))}
The following code returns nothing
() => { const value = 1; }
The following code returns 1
() => { const value = 1; return value;}
The following code returns 1
() => 1
I have an array of objects that are suposed to pass as props to a element to render a list for each object, but when I try the code only one its rendered and the others are ignored even though I've console.log them and I can see them. Here's the code:
const mainFilterQueries = ['popular', 'top_rated', 'upcoming']
const sortByMovies = "movie"
const [moviesLists, setMoviesLists] = useState([])
useEffect(()=>{
createLists(mainFilterQueries, sortByMovies , setMoviesLists, moviesLists)
console.log(moviesLists)
}, [])
async function fetchData(query, sort, setMethod, state){
let listsCreated = []
try {
const response = await fetch(`https://api.themoviedb.org/3/${sort}/${query}?api_key=${apikey}`)
const data = await response.json();
let dataObject = {key:`${sort}-${query}`, data:data.results, title:`${query}`}
console.log(dataObject)
listsCreated.push(dataObject);
setMethod([...state, dataObject])
} catch (error) {
console.error(error)
}
}
function createLists(arr, sort, target, state){
arr.forEach(query =>{
fetchData(query, sort, target, state)
})
}
return (
<React.Fragment>
{moviesLists.map(list =>{
return(
<div>
<MoviesList dataList={list}/>
</div>
)
})}
</React.Fragment>
)
You're calling setMethod([...state, dataObject]) in a loop. state will never be updated until the next render, meaning you're actually calling the function as if it were like this: setMethod([...[], dataObject]) for every iteration.
Instead use the functional update form of setState like this:
setMethod((prev) => ([...prev, dataObject]))
The functional update ensures that the previous state is most up-to-date with any previous calls to setMethod.
See also why-calling-react-setstate-method-doesnt-mutate-the-state-immediately.