API gives back an array but data not showing on screen - javascript

I'm trying to show some tickets on the screen from an APi. I did the petition with a fetch and the console is showing me an array with the data that I want to be shown on screen.
Everything seems to be okay but the tickets ain't in the screen.
here is the array showing on the console
render() {
return (
<article>
<section className="container">
{this.state.tickets.map((ticket) => (
<div onClick={this.onclicked} key={ticket.id}>
{this.state.clicked === true && (
<div className="boxinfo">
<h1 className="info">{ticket.fecha_adquisicion}</h1>
<h2 className="info">{ticket.id_comercio}</h2>
<h3 className="info">{ticket.precio_total}</h3>
</div>
)}
</div>
))}
</section>
</article>
);
}
That's the render method I did. I was thinking about the undefined " REACT_APP_SERVER_URL: " the console is showing from my api, it could may be the function I did on the API isn't right?
Thanks

I had this problem before.
What is happening here that you are not returning something from the .map() function
it should be fixed by doing this
render() {
return (
<article>
<section className="container">
{this.state.tickets.map((ticket) => {
return <div onClick={this.onclicked} key={ticket.id}>
{/* your code*/}
</div>
)}}
</section>
</article>
);
}

Related

render specific text based on Conditional statement

I have the following JSON
{"location":"2034","type":"Residential","price":400000,"address":"123 Fake Street","suburb":"Maroubra","historical_DAs":0,"description":"Residential","property_ID":1},
{"location":"2036","type":"Commercial","price":475000,"address":"123 Fake Street","suburb":"Coogee","historical_DAs":10,"description":"Government","property_ID":2},
{"location":"2035","type":"Food & Bev","price":56000,"address":"123 Fake Street","suburb":"Clovelly","historical_DAs":3,"description":"Residential","property_ID":3},
{"location":"2031","type":"Education","price":69070,"address":"123 Fake Street","suburb":"Randwick","historical_DAs":7,"description":"Government","property_ID":4},
{"location":"2036","type":"Education","price":69070,"address":"123 Fake Street","suburb":"Randwick","historical_DAs":7,"description":"Government","property_ID":5}
I want to render different images based upon the description field (currently trying to just get text to render correctly atm.)
What I have tried so far:
function TypeImages({ description }) {
function Residential(props) {
return <div>
<h1>Image 1</h1>
</div>;
}
function Government(props) {
return <div>
<h1>Image 2 </h1>
</div>;
}
function TypeImage(props) {
if (description === 'Residential') {
return <Residential />;
} else
return <Commercial />;
}
return (
<div>
<div>
<div className="hidden lg:inline-flex mb-1 px-9">
<TypeImage/>
<div>
</div>
</div>
</div>
</div>
);
}
export default TypeImages;
This isn't working as what is rendered is all 'Image 2' even though there should be some 'Image 1'
Any suggestions on the most efficient way to achieve this?
Thanks!
You can do by many ways,
You need to make sure or check if description has value, if not you probably get unexpected behaviors
Sandbox Example: https://codesandbox.io/s/stupefied-water-sc4o5h?file=/src/App.js
Using ternary conditional statements
return (
<div>
<div>
<div className="hidden lg:inline-flex mb-1 px-9">
{/* Doing this */}
{description === "Residential" ? <Residential /> : <Government /> }
<div>
</div>
</div>
</div>
</div>
);
Doing the way that you was working
function TypeImage() {
if (description === 'Residential') {
return <Residential />;
}
return <Government/>;
}
return (
<div>
<div>
<div className="hidden lg:inline-flex mb-1 px-9">
<TypeImage/>
<div>
</div>
</div>
</div>
</div>
);
Doing this another way using conditional inline
return (
<div>
<div>
<div className="hidden lg:inline-flex mb-1 px-9">
{description === "Residential" && <Residential /> }
{description === "Government" && <Government/> }
<div>
</div>
</div>
</div>
</div>
);

React infinite/max-level comment for each news post

I have a News feature where user can post their status. However, so far, I cannot make it display all comments of the news as my current solution only allows two-level only. Here are my codes:
News.js (for all)
function News() {
const {userId, setUserId} = useContext(UserContext);
const {type, isUserType} = useContext(UserTypeContext);
const [newsList, setNewsList] = useState([]);
const rootNews = newsList.filter(
(newList) => newList.reply_of === null
);
const getReplies = commentId => {
return newsList.filter(newList => newList.reply_of === commentId);
}
useEffect(()=>{
Axios.get('http://localhost:3001/news',{
})
.then((response) => {
if(response.data.length > 0){
setNewsList(response.data);
}
})
},[]);
return (
<div className = "news p-5">
<h3 className="news-title">News</h3>
<div className = "comments-container">
{rootNews.map((rootNew) => (
<div>
<Comment key={rootNew.news_id}
comment={rootNew}
replies={getReplies(rootNew.news_id)}/>
</div>
))}
</div>
</div>
)
}
Comment.js (for rendering the comments and replies)
function Comment({comment, replies}) {
return (
<div className="comment">
<div className="comment-image-container">
<img src = "/user-icon.png" />
</div>
<div className="comment-right-part">
<div className="comment-content">
<div className="comment-author">
{comment.user_name}
</div>
<div>{comment.day}, {moment(comment.date).format('DD-MM-YYYY')} at {comment.time}</div>
</div>
<div className="comment-text">{comment.news_title}</div>
{replies.length > 0 && (
<div className="replies">
{replies.map(reply => (
<Comment comment={reply} key={reply.news_id} replies={[]}/>
))}
</div>
)}
</div>
</div>
)
}
This is an example on how the comment structure would look like:
Comment 1
Reply 1.1
Reply 1.1.1
Reply 1.1.1.1
Reply 1.2
Comment 2
An idea on how I could render infinite replies, or possibly set the maximum level of replies allowed? Thank you
You just need a little change to the Comment component to recursively render the already nested data structure:
function Comment({ comment, newsList }) {
const replies = newsList.filter((newList) => newList.reply_of === comment.news_id);
return (
<div className="comment">
<div className="comment-image-container">
<img src="/user-icon.png" />
</div>
<div className="comment-right-part">
<div className="comment-content">
<div className="comment-author">{comment.user_name}</div>
<div>
{comment.day}, {moment(comment.date).format("DD-MM-YYYY")} at{" "}
{comment.time}
</div>
</div>
<div className="comment-text">{comment.news_title}</div>
{replies.length > 0 && (
<div className="replies">
{replies.map((reply) => (
<Comment key={reply.news_id} comment={reply} newsList={newsList} />
))}
</div>
)}
</div>
</div>
);
}
Basically, you just move the code that gets the direct replies to a comment into the Comment component.
When you render the root Comment component, all direct replies to the root comment will be identified and will cause the rendering of nested Comment components, which will in turn identify the replies to the reply, render a nested Comment component and so on.

Can't access nested Objects JSON in React JSX

I can access JSON objects in the results here
useEffect(() => {
fetch(`/user/${userid}`,{
method:'get',
headers:{
"Authorization":`Bearer ${localStorage.getItem('token')}`}
}).then(res=>res.json())
.then(result=>{
console.log(result.user.name) //I can access JSON objects in the results here//
setProfile(result)
})
.catch(err=>console.log(err))
}, [])
I can access JSON while Changing State but it throws errors like UserProfile.user is undefined,UserProfile.posts.length is undefined when rendering JSX. TO access the nested Data I have tried creating more state Variables. It works but the code have become long. I looked for solution in various website but could not find. Any one help me.
return (
<>
{
UserProfile?<div style={{maxWidth:'800px',margin:"0px auto"}}>
<div style={{
display:"flex",
justifyContent:'space-around',
margin:"18px 0px"
}}>
<div>
<img style={{borderBottom:"1px solid grey",width:"160px",height:"160px",borderRadius:"80px"}} src="https://images.unsplash.com/photo-1569466896818-335b1bedfcce?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=60"/>
</div>
<div>
<h4>{UserProfile?UserProfile.user.name:"Loading..."}</h4>
<div style={{display:"flex",justifyContent:"space-between",width:"100%"}}>
<h6>{UserProfile.posts.length} posts </h6>
<button onClick={()=>followUser()} className="btn waves-effect waves-light #64b5f6 blue lighten-2" type="button" name="action">Follow</button>
</div>
</div>
</div>
<div className="gallery">
{
UserProfile.posts.map((item)=>{
return(
<img className="item" key={item._id} src={item.photo}/>
)
})
}
</div>
</div>:
<h1>Loading:</h1>
}
</>
)
export default Profile
Based on the code and your inputs, the problem may be because you are trying to access the variables before they are accessible.
As you are making async API call in useEffect() it may take some time before you get data. But, as you are accessing the data before you even get it errors like 'UserProfile.user is undefined', 'UserProfile.posts.length' is undefined will occur'
To avoid such errors make sure you add a check as shown below
<>
{
UserProfile &&
<div style={{maxWidth:'800px',margin:"0px auto"}}>
<div style={{
display:"flex",
justifyContent:'space-around',
margin:"18px 0px"
}}>
<div>
<img style={{borderBottom:"1px solid grey",width:"160px",height:"160px",borderRadius:"80px"}} src="https://images.unsplash.com/photo-1569466896818-335b1bedfcce?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=60"/>
</div>
<div>
/* -----> modify it here*/ <h4>{UserProfile ? UserProfile.user && UserProfile.user.name:"Loading..."}</h4>
<div style={{display:"flex",justifyContent:"space-between",width:"100%"}}>
/* -----> modify it here*/ <h6>{UserProfile && UserProfile.posts && UserProfile.posts.length} posts </h6>
<button onClick={()=>followUser()} className="btn waves-effect waves-light #64b5f6 blue lighten-2" type="button" name="action">Follow</button>
</div>
</div>
</div>
<div className="gallery">
{
UserProfile.posts.map((item)=>{
return(
<img className="item" key={item._id} src={item.photo}/>
)
})
}
</div>
</div>
:
<h1>Loading:</h1>
}
</>
I got the solution for this. I got rid of this problem by setting initial state to null. Thank You for answering my query.
//my initial useState declaration//
const [userProfile,setUserProfile]=useState([])
//Solution//
const [userProfile,setUserProfile]=useState(null)
I am new to react so I got into problem.

Cards inside the grid-container: each child in a list should have a unique "key" prop

What I`m doing wrong?It also says: "Check the render method of Card" , which is here:
<div className="grid-container">
{pokemonData.map((pokemon, i) => {
console.log(pokemon.id) // unique numbers are here
return <Card key={pokemon.id} pokemon={pokemon} />
})}
</div>
Card component itself:
function Card({ pokemon }) {
return (
<div className="card">
<div className="card__image">
<img src={pokemon.sprites.front_default} alt="Pokemon" />
</div>
<div className="card__name">
{pokemon.name}
</div>
<div className="card__types">
{
pokemon.types.map(type => {
return (
<div className="card__type" style={{backgroundColor: typeColors[type.type.name]}}>
{type.type.name}
</div>
)
})
}
</div>
<div className="card__info">
<div className="card__data card__data--weight">
<p className="title">Weight:</p>
<p>{pokemon.weight}</p>
</div>
<div className="card__data card__data--height">
<p className="title">Height:</p>
<p>{pokemon.height}</p>
</div>
<div className="card__data card__data--ability">
<p className="title">Abilities:</p>
{/* {console.log(pokemon.abilities)} Temporary for dev puprose */}
{pokemon.abilities.map(ability => <p>{ability.ability.name}</p>
)}
</div>
</div>
</div>
);
}
export default Card;
You can use the index of the array may be your data is having some kind of duplicate. It is recommended that you pass a key prop whenever you are returning a list.
<div className="grid-container">
{pokemonData.map((pokemon, i) => {
console.log(pokemon.id) // unique numbers are here
return <Card key={i} pokemon={pokemon} />
})}
</div>
Equally, check this segment of card components.
{
pokemon.types.map((type,i) => {
return (
<div key={i} className="card__type" style={{backgroundColor:
typeColors[type.type.name]}}>
{type.type.name}
/div>
)
})
}
And
<div className="card__data card__data--ability">
<p className="title">Abilities:</p>
{/* {console.log(pokemon.abilities)} }
{pokemon.abilities.map((ability, i) => <p key={i}>{ability.ability.name}
</p>
)}
</div>
Previous answer will solve your problem. However, for your info, I would also like to add here.
For React a key attribute is like an identity of a node/element/tag which helps React to identify each item in the list and apply reconciliation correctlyon each item. Without a key React will render your component but may cause issue when you re-order your list.
React recommends to use id of the data instead of index number. However, if your list does not re-orders/ sorts or do not have id then you can use index.
You can read more here:
https://reactjs.org/docs/lists-and-keys.html
Change this:
<div className="card__types">
{
pokemon.types.map(type => {
return (
<div className="card__type"
style={{backgroundColor:typeColors[type.type.name]}}
>
{type.type.name}
</div>
)
})
}
</div>
to:
<div className="card__types">
{
pokemon.types.map((type, key) => {
return (
<div key={key} className="card__type"
style={{backgroundColor:typeColors[type.type.name]}}
>
{type.type.name}
</div>
)
})
}
</div>
and:
{pokemon.abilities.map(ability => <p>{ability.ability.name}</p>
to:
{pokemon.abilities.map((ability,key) => <p key={key} >{ability.ability.name}</p>

Cannot Render Nested Maps In ReactJS

I am trying to nest maps to render an array within an object
My Cards Component Render Method (Not Nested, Working):
render() {
return (
<div class="mediator-container">
{this.state.routeList.map(
(route, index) =>
<Card busName={this.state.routeList[index].$.tag} />
)}
<span class="loader">
<span class="loader-inner"></span>
</span>
</div>
);
}
My Cards Component Render Method (Nesteing, Not Working!!):
render() {
return (
<div class="mediator-container">
{this.state.routeList.map((route, index) =>
{
{
this.busTitleToDirectionName(this.state.routeList[index].$.tag).map(busDir => {
<Card busName={busDir} />;
});
}
}
)}
<span class="loader">
<span class="loader-inner"></span>
</span>
</div>
);
}
busTitleToDirectionName(int) returns an array of Strings
My Card Subcomponent's render method:
render() {
// Logging to see if render method is called
console.log("Ran");
return (
<div className="card">
<div className="card-header">
<div className="bus-name">
<p>{this.props.busName}</p>
</div>
</div>
</div>
);
}
How it looks like without nesting when it does work (Not enough reputation to post images so here are the links):
https://i.gyazo.com/66414925d60701a316b9f6325c834c12.png
I also log in the Card subcomponent so that we know that the Card component was ran and it logs that it did get called without nesting
https://i.gyazo.com/fb136e555bb3df7497fe9894273bf4d3.png
When nesting, nothing renders and the Card subcomponent isn't being called as there is no logging of it
https://i.gyazo.com/38df248525863b1cf5077d4064b0a15c.png
https://i.gyazo.com/d6bb4fb413dfc9f683b44c88cce04b8a.png
You can try below code in your nested case. In the nesting of map you have to wrap your nested map within a container. Here I use React.Fragment (<> ) as a container.
return (
<div class="mediator-container">
{this.state.routeList.map((route, index) =>
<>
{
this.busTitleToDirectionName(this.state.routeList[index].$.tag).map(busDir => {
<Card busName={busDir} />;
});
}
</>
)}
<span class="loader">
<span class="loader-inner"></span>
</span>
</div>
);
Hope it will help you!!
Thanks, Prahbat Kumar, but I figured out the issue. I had to return the subcomponent from the nested map here is the code:
render() {
return (
<div class="mediator-container">
{this.state.routeList.map((route, index) =>
this.busTitleToDirectionName(this.state.routeList[index].$.tag).map(busDir => {
return <Card busName={busDir} />
})
)}
<span class="loader">
<span class="loader-inner"></span>
</span>
</div>
);
}

Categories

Resources