Cannot read property 'map' of undefined in react while passing through props - reactjs

I am building simple react application it showing map is undefine please resolve this error it might help a lot
child code
const classes = useStyles()
const {qnsObject,answersList} = props.value
console.log(qnsObject,answersList)
return (
qnsObject.map((content,index) =>{
let count = content.tags.split(',')
return (
<div className = {classes.homeRecentQns} >
<div className ={classes.homeRecentQnsParent}>
<div className = {classes.avatar_parent}>
<div className ={classes.avatar}>
<Avatar alt='tfds' src ={content.profile_img} className
= {classes.small}>{content.firstName[0].toUpperCase()}</Avatar>
</div>
<div className ={classes.voted_parent}>
<ArrowDropUpTwoToneIcon className =
{classes.voted_up}/>
<p>125</p>
<ArrowDropDownTwoToneIcon className =
{classes.voted_down}/>
</div>
</div>
<div className ={classes.recentQns_parent}>
<div className = {classes.recentQns_tags_parent}>
<p className = {classes.recentQns_name}>
{content.firstName} {content.lastName}</p>
<p className = {classes.recentQns_occupation}>
{content.currentWorking}</p>
<p className = {classes.recentQns_askedIn}><b
className = {classes.recentQns_askedIn_bold}>Asked in:
</b>{content.posted_date}</p>
</div>
<div className ={classes.recentQns_desc}>
<p className ={classes.recentQns_title}>
{content.qnsTitle}</p>
<p className ={classes.recentQns_answers}>
{ReactHtmlParser(content.Question_body)}
</p>
</div>
<div className ={classes.recentQns_topic_tags}>
{content.tags.split(',').map(chip =>{
return <> <Chip label={chip} variant="filled"
color="primary" size="small" icon=
{<LocalOfferTwoToneIcon />} /></>
})}
</div>
<div className ={classes.recentQns_views_parent}>
<div className = {classes.popular_desc_view}>
<QuestionAnswerIcon className =
{classes.views_icon}/>
<div className = {classes.p}>
{answersList.length} Answers</div>
</div>
<div className = {classes.popular_desc_view}>
<VisibilityIcon className =
{classes.views_icon}/>
<div className = {classes.p}>5 views</div>
</div>
</div>
</div>
</div>
</div>
)
})
)
parent code
const Auth = useContext(Authapi)
const [body,setBody] = useState("")
const [open, setOpen] = React.useState(false);
const [dataQns,setDataqns] = useState([])
const [closeAns, setAns] = React.useState(false);
let href = window.location.href.split('/')
console.log(dataQns)
const classes = useStyles()
useEffect(() =>{
const get = async () =>{
const data = await fetch('/getAnswers/'+href[href.length -1])
const dataItems = await data.json()
console.log(dataItems)
setDataqns(dataItems)
}
get()
},[dataQns])
this props I passing
<ViewPostComponent value = {dataQns}/>
how to get update when new data is ready to render using hooks please answer to this question
how to update map function when new data getting from server

map is undefined means that you have not passed any data to the map() function

You can use content loading before api call
{!!dataQns ? (<ViewPostComponent value = {dataQns}/> ) : (<SomeLoadingSvgAnimationComponent>) }

Probably you are mapping an empty array or a variable that is not an array.
You can check the length before mapping.
{
variable.length > 0 && variable.map((e) => your code )
}
Update
Instead of using just a variable, you need to use React State.
When data is loaded, set the data into the state and everything will work.

{qnsObject && qnsObject.map((content,index)........}
Try this while mapping. Mapping will occur only when qnsObject is an array else it will return null.

Related

Code duplication: how to avoid in Reactjs

Expectation: if the flag is true, then empty div "container" around div "content"
const Demo = () => {
const [flagABC] = useFlagFeature(true)
return (
<div className="featureflagoff"> style= {} onMouseEnter = {} //if feature flag is off || if feature flag is ON then empty div
<div className="content">
// huge code
<div>
</div>
);
}
how can i avoid copying the ("huge code") twice.
Assign the huge code to a variable and reference it.
const hugeCode = <div>...</div>
return (
<div className="featureflagoff">
<div className="content">
{hugeCode}
<div>
</div>
);
Assuming flagABC is the flag, you can do something like this:
const Demo = () => {
const [flagABC] = useFlagFeature(true)
return (
<div className={flagABC ? "" : "featureflagoff"}>
<div className="content">
// huge code
<div>
</div>
);
}

reactJs useRef to add or Remove className

How to Add className or Remove ClassName using useRef
code follows
const refs = useRef("");
const clicka =()=>{ ref.current.classList.add('correct') }
<div onClick={()=>{clicka()}} refs={ref} className="js-choose-answer"><div>a</div>{user.opt1}</div></div>
i can Access className Value ref.current.className but unable to add
code
import React, { useState, useEffect,useRef} from 'react';
const Slugg = ({user}) => {
//onClick to set className "js-choose-answer correct"
return (
<div>
<div className="__options">
<div onClick={()=>{clicka(user._id)}} ref={ref} className="js-choose-answer"><div>a</div><{user.opt1} </div></div>
</div>
<div className="__options">
<div onClick={()=>{clicka(user._id)}} ref={ref} className="js-choose-answer"><div>a</div><{user.opt1} </div></div>
</div>
</div>
)
}
Try this using useState. Set a boolean corresponding to user id which rerenders the elements with classname correct
const [status, setStatus] = useState({});
const clicka =(userId)=>{
setStatus(prevStatus=>{
return {...prevStatus, [userId]: true}
})
}
<div onClick={()=>{clicka(user._id)}} className={`js-choose-answer ${status[user._id] ? 'correct': ''}`}><
<div>a</div><{user.opt1} </div></div>
</div>
I usually do this and it works
const currentElement = useRef(null)
const switchClassHandler = () => {
currentElement.current.classList.add('correct')
currentElement.current.classList.remove('error')
}
return (
<React.Fragment>
<div ref={currentElement} onClick={switchClassHandler} className={'global error'}>
hello
</div>
</React.Fragment>
)

How to get specific data from api with condition

Hello so i tried to make an website using Goole Books API. I want to get the listPrice from the object, but theres some of the book that doesnt have the listPrice in them. So for the example in object number 1 there is some code called saleability: "NOT_FOR_SALE" meanwhile object number 2 have and saleability: "FOR_SALE". If i tried to map the data, there is a error Uncaught TypeError: i.saleInfo.saleability.listPrice is undefined. How do you make spesific condition for this problem.
This is the code :
const CardBooks = (props) => {
const url = "https://www.googleapis.com/books/v1/volumes?q=:keyes&key=AIzaSyDIwDev4gFHRqCh4SSaO9eLKEeI7oYt6aE&maxResults=27"
const result = "&maxResults=40"
const [bookHome, setBookHome] = useState([]);
const [modalShow, setModalShow] = React.useState(false);
useEffect( () => {
axios
.get(`${url}`)
.then( (res) => {
setBookHome(res?.data?.items)
console.log(res?.data?.items)
})
.catch(console.error);
}, [])
return (
<div>
<Container fluid className='wrapper'>
{bookHome && bookHome.map((i, index) => {
return(
<div className='image-container' key={index}>
<div className="book read">
<div className="cover">
<img src={i.volumeInfo.imageLinks.thumbnail} />
</div>
<div className="info">
<h3 className="title">{i.volumeInfo.title}</h3>
</div>
<Example
thumbnail={i.volumeInfo.imageLinks.thumbnail}
title={i.volumeInfo.title}
description={i.volumeInfo.description}
category={i.volumeInfo.categories}
page={i.volumeInfo.pageCount}
language={i.volumeInfo.language}
publisher={i.volumeInfo.publisher}
published={i.volumeInfo.publishedDate}
link={i.volumeInfo.previewLink}
epub={i.accessInfo.epub.isAvailable}
currency={i.saleInfo.saleability.listPrice.currencyCode}
price={i.saleInfo.saleability.listPrice.amount}
/>
</div>
</div>
)
})}
</Container>
</div>
)
}
export default CardBooks
Basically you just need a null/undefined check, a quick and dirty solution:
currency={i.saleInfo.saleability.listPrice ? i.saleInfo.saleability.listPrice.currencyCode : ''}
It's better to use conditional rendering and/or passing the whole object to the component and handling it inside.

Rendering an array of objects in React but it says objects cant be child elements

I am storing the response from an API in an array called Products. This array stores the objects returned. I am displaying the title property of the objects in a div. But getting objects cant be child elements in React error. What should I do?
Also, I have tried rendering the products title (eg: Products[0].title) but even this doesn't work. But this is not an object. So why doesn't this work?
Code on React:
const App = () => {
const [Elec,setElec] = useState("");
const [Jewe,setJewe] = useState("");
const [MJ,setMJ] = useState("");
const [WMJ,setWMJ] = useState("");
const [Products,setProducts] = useState([]);
const fetcher = (e) => {
fetch('https://fakestoreapi.com/products/categories')
.then(res=>res.json())
.then(json=>{
console.log(json);
setElec(json[0]);
setJewe(json[1]);
setMJ(json[2]);
setWMJ(json[3]);
console.log(setElec);
})
}
const jewelleryproducts = () =>{
fetch('https://fakestoreapi.com/products/category/jewelery')
.then(res=>res.json())
.then(json=>{console.log(json);
setProducts(json);
console.log(Products);
})
}
return(
<>
<Head>
<link rel="stylesheet" href="./css/general.css"></link>
</Head>
<div>
<div className="searchbardiv">
<input type="text" placeholder="Search"></input>
<img src="./images/cart.png" typ></img>
<img src="./images/avatar.jpg"></img>
</div>
<div className="categories">
<div> <button
type="submit"
onClick={e => {fetcher()}}
>Show all categories</button></div>
<ol>
<li><a>{MJ}</a> </li>
<li><a>{WMJ}</a></li>
<li><a>{Elec}</a> </li>
<li><button type="submit" onClick={ e => {jewelleryproducts()}}>{Jewe}</button></li>
</ol>
</div>
<div className="jewelleryproducts">
<div>{Products[0]}</div>
<div>{Products[1]}</div>
<div>{Products[2]}</div>
<div>{Products[3]}</div>
</div>
</div>
</>
)
}
export default App;
you can do this
<Select>
{list.map((el) => (
<Option key={el.code} value={=el.code}>
{el.name}
</Option>
))}
</Select>
You need to .map() over the array and define what you should be displayed for every iteration.
Example:
<div className="jewelleryproducts">
{Products.map(product => (
<div>{product}</div>
)}
</div>
This also prevents the code duplication.
Note: this example is based on the assumption that each product is a string.
If that's not the case, then it should be adjusted accordingly.

Use State not updating as expected

Fairly new to react and trying to build a clone of The Movie Database site. I want this toggle switch to change my api call from movies to tv. It starts working after a couple clicks, but then it throws everything off and it's not displaying the correct items anyway. Not really sure what's going on here...or even why it starts working after two clicks. Anyone know whats up with this?
import React, { useState, useEffect } from "react";
import axios from "axios";
import API_KEY from "../../config";
const Popular = ({ imageUri }) => {
// GET POPULAR MOVIES
const [popularMovies, setPopularMovies] = useState("");
const [genre, setGenre] = useState("movie");
console.log(genre);
const getPopular = async () => {
const response = await axios.get(
`https://api.themoviedb.org/3/discover/${genre}?sort_by=popularity.desc&api_key=${API_KEY}`
);
setPopularMovies(response.data.results);
};
useEffect(() => {
getPopular();
}, []);
const listOptions = document.querySelectorAll(".switch--option");
const background = document.querySelector(".background");
const changeOption = (el) => {
let getGenre = el.target.dataset.genre;
setGenre(getGenre);
getPopular();
listOptions.forEach((option) => {
option.classList.remove("selected");
});
el = el.target.parentElement.parentElement;
let getStartingLeft = Math.floor(
listOptions[0].getBoundingClientRect().left
);
let getLeft = Math.floor(el.getBoundingClientRect().left);
let getWidth = Math.floor(el.getBoundingClientRect().width);
let leftPos = getLeft - getStartingLeft;
background.setAttribute(
"style",
`left: ${leftPos}px; width: ${getWidth}px`
);
el.classList.add("selected");
};
return (
<section className="container movie-list">
<div className="flex">
<div className="movie-list__header">
<h3>What's Popular</h3>
</div>
<div className="switch flex">
<div className="switch--option selected">
<h3>
<a
data-genre="movie"
onClick={(e) => changeOption(e)}
className="switch--anchor"
>
In Theaters
</a>
</h3>
<div className="background"></div>
</div>
<div className="switch--option">
<h3>
<a
data-genre="tv"
onClick={(e) => changeOption(e)}
className="switch--anchor"
>
On TV
</a>
</h3>
</div>
</div>
</div>
<div className="scroller">
<div className="flex flex--justify-center">
<div className="flex flex--nowrap container u-overScroll">
{popularMovies &&
popularMovies.map((movie, idX) => (
<div key={idX} className="card">
<div className="image">
<img src={imageUri + "w500" + movie.poster_path} />
</div>
<p>{movie.title}</p>
</div>
))}
</div>
</div>
</div>
</section>
);
};
export default Popular;
You're using the array index as your key prop when you're mapping your array.
You should use an id that is specific to the data that you're rendering.
React uses the key prop to know which items have changed since the last render.
In your case you should use the movie id in your key prop instead of the array index.
popularMovies.map((movie) => (
<div key={movie.id} className="card">
<div className="image">
<img src={imageUri + 'w500' + movie.poster_path} />
</div>
<p>{movie.title}</p>
</div>
));
Also
You're calling the api directly after setGenre. However state changes aren't immediate. So when you're making your api call you're still sending the last movie genre.
Two ways of fixing this:
You could call your function with the genre directly, and change your function so it handles this case:
getPopular('movie');
Or you could not call the function at all and add genre as a dependency of your useEffect. That way the useEffect will run each time the genre change.
useEffect(() => {
getPopular();
}, [genre]);
PS: You should consider splitting your code into more component and not interacting with the DOM directly.
To give you an idea of what it could look like, I refactored a bit, but more improvements could be made:
const Popular = ({ imageUri }) => {
const [popularMovies, setPopularMovies] = useState('');
const [genre, setGenre] = useState('movie');
const getPopular = async (movieGenre) => {
const response = await axios.get(
`https://api.themoviedb.org/3/discover/${movieGenre}?sort_by=popularity.desc&api_key=${API_KEY}`
);
setPopularMovies(response.data.results);
};
useEffect(() => {
getPopular();
}, [genre]);
const changeHandler = (el) => {
let getGenre = el.target.dataset.genre;
setGenre(getGenre);
};
const isMovieSelected = genre === 'movie';
const isTvSelected = genre === 'tv';
return (
<section className="container movie-list">
<div className="flex">
<MovieHeader>What's Popular</MovieHeader>
<div className="switch flex">
<Toggle onChange={changeHandler} selected={isMovieSelected}>
In Theaters
</Toggle>
<Toggle onChange={changeHandler} selected={isTvSelected}>
On TV
</Toggle>
</div>
</div>
<div className="scroller">
<div className="flex flex--justify-center">
<div className="flex flex--nowrap container u-overScroll">
{popularMovies.map((movie) => {
const { title, id, poster_path } = movie;
return (
<MovieItem
title={title}
imageUri={imageUri}
key={id}
poster_path={poster_path}
/>
);
})}
</div>
</div>
</div>
</section>
);
};
export default Popular;
const Toggle = (props) => {
const { children, onChange, selected } = props;
const className = selected ? 'switch--option selected' : 'switch--option';
return (
<div className={className}>
<h3>
<a
data-genre="movie"
onClick={onChange}
className="switch--anchor"
>
{children}
</a>
</h3>
<div className="background"></div>
</div>
);
};
const MovieHeader = (props) => {
const { children } = props;
return (
<div className="movie-list__header">
<h3>{children}</h3>
</div>
);
};
const MovieItem = (props) => {
const { title, imageUri, poster_path } = props;
return (
<div key={idX} className="card">
<div className="image">
<img src={imageUri + 'w500' + poster_path} />
</div>
<p>{title}</p>
</div>
);
};

Resources