I'm trying to do conditional rendering in React (only maps and renders when props exist).
render() {
if (this.props.res) {
return(
<div>{this.props.res.map(item => <li key={item.id}>{item.subreddit}</li>}</div>
)
} else {
return null
}
}
But I have this error:
Parsing error: Unexpected token, expected ","
Why is that, and how can I fix it? Or in another way, is there a better way to achieve my purpose?
There is syntax error, map(...) doesn't have closing parenthesis.
It should be:
<div>{this.props.res.map(item => <li key={item.id}>{item.subreddit}</li>)}</div>
Here are the issues I see:
map is missing the closing parenthesis
check the array length (an empty array will return true otherwise)
list items should be wrapped with an appropriate tag, such as <ul/>
render() {
const { res } = this.props;
return !res.length ? null : (
<ul>{res.map(item => <li key={item.id}>{item.subreddit}</li>)}</ul>
);
}
there was a brace missing in the end of the map.
render() {
return (
<div>
{
this.props.res && this.props.res.map(item => (
<li key={item.id}>{item.subreddit}</li>
))
}
</div>
);
}
render() {
if (this.props.res) {
return (
<div>
{this.props.res.map(item => (
<li key={item.id}>{item.subreddit}</li>
))}
</div>
);
} else {
return null;
}
}
Related
I've got a list of products to render. I also have an array of keywords that are used to exclude products from being rendered.
I am looping over the array of keywords and checking if the product title contains any of the entries. It then returns a boolean.
The following code does not work. The console.log works and reflects the result but nothing is rendered.
function inExcludes(product, excludedItems) {
excludedItems.forEach( item => {
if (product.includes(item)) {
console.log(true);
return true;
} else {
console.log(false);
return false;
}
})
}
export function CardsFiltered(props) {
const cards = props.items.map((product) => {
if (inExcludes(product.title, props.excludedItems) === false)
return (
<CardValidation
key={product.id}
id={product.id}
product={product}
/>
)
})
return (
<>
{cards}
</>
);
}
But if I set a variable as a boolean, switch that variable if the condition is true, and then return that variable, it works and my cards are rendered (code below).
Is anyone able to shed light on this? Because I can't figure it out.
function inExcludes(product, excludedItems) {
let result = false;
excludedItems.forEach( item => {
if (product.includes(item)) {
result = true;
}
})
return result;
}
export function CardsFiltered(props) {
const cards = props.items.map((product) => {
if (!inExcludes(product.title, props.excludedItems))
return (
<CardValidation
key={product.id}
id={product.id}
product={product}
/>
)
})
return (
<>
{cards}
</>
);
}
Your first implementation of 'inExcludes' isn't returning a boolean (true/false). It's just executing the 'forEach' on each item in the excludedItems array. The return within that loop doesn't return from the function as a whole.
So, as it effectively returns 'undefined' your render decides not to render anything.
Here's something that does what you're after (simplified a bit):
https://codesandbox.io/s/awesome-mcclintock-hkkhsi?file=/src/App.js
I'm trying to return an HTML element or another depending on some conditions calculated on Javascript. I tried doing this, but I can't start the condition with and if, I don't understand why.
My component file is this one:
import React from 'react';
import defaultImage from './defaultImage.jpg';
export default class Game extends React.Component {
render() {
const image = this.props.question.attachment.url;
const tips = this.props.question.tips;
return (
<div className="flexDisplay">
<img src={image === (null || "") ? defaultImage : image} className="questionImage centerVertical" alt="Error loading, just read the question" />
<div className="centerHorizontal centerVertical">
<h1>{this.props.question.question}</h1>
<h2 className="centerHorizontal">Pistas:</h2>
{
if(tips.length === 0){ //The problem comes here
return <div>No hay pistas disponibles</div>
}else{
tips.map((tip, i,) => {
return <div className="centerHorizontal" key={tip.toString()}>{i+1}. {tip}</div>;
})
}
}
</div>
</div>
);
}
Anyone spot the problem?
You can not use if statements inside JSX syntax. Instead you can use the ternary operator which basically accomplish the same :
{
tips.length === 0 ?
(<div>No hay pistas disponibles</div>)
: (tips.map((tip, i,) => {
return <div className="centerHorizontal" key={tip.toString()}>{i+1}. {tip}</div>;
}));
}
In ReactJS's component ( JSX ) you are not allowed to use anything else than a statement that returns a value.
You can imagine the logic by trying to assign a variable :
const result = if ( a ) { "b" } else { "c" } // won't work
But on the other hand with a Ternary Operator it will.
const result = a ? "b" : "c";
So in your case there are two ways of achieving the goal :
{ tips.length === 0 ? ( <div>No hay pistas disponibles</div> ) : (
tips.map((tip, i) => (
<div className="centerHorizontal" key={ tip.toString() }>{i+1}. {tip}</div>
) )
) }
Or you can simply extract that in a method
renderTips( tips ) {
if ( tips.length === 0 ) { return null; }
return tips.map( ( tip, i ) => (
<div className="centerHorizontal" key={ tip.toString() }>{i+1}. {tip}</div>
);
}
render() {
...
return (
...
{ this.renderTips( tips ) }
)
}
You're not able to use "if" in inline conditional statements in jsx. You can however use the ternary syntax instead:
{
tips.length === 0 ? (
return <div>No hay pistas disponibles</div>
) : (
tips.map((tip, i,) => {
return <div className="centerHorizontal" key={tip.toString()}>{i+1}. {tip}</div>;
})
)
}
You can read more about using inline conditional statements here: https://reactjs.org/docs/conditional-rendering.html#inline-if-with-logical--operator
I'm trying to do nested conditionals to be rendered and one case would make me use .map()
renderClasses () {
if (!this.state.classes.length) {
console.log(this.state.userType)
if (this.state.userType) return(<div>Add Class</div>)
else return (<div>Join Class</div>)
} else {
return (<div>{
this.state.classes.map((class) => {
^ unexpected token here
<div>one class</div>
})
}</div>)
}
}
render() {
if (!this.state.isLogged) {
return <Redirect to='/' />
}
return (
<div>
{
this.renderClasses()
}
</div>
);
}
Am i missing something? i tried wrapping everything into one <div> or maybe I understood it wrong? Thank you in advance
you do not return anything:
this.state.classes.map((item) => {
<div>one class</div>
})
try to paste return statement
this.state.classes.map((item) => {
return <div>one class</div>
})
But the error is cause by class being a reserved keyword, try to name it like item.
If you use {} in map function you need to use return as well. If its just a single statement, just ignore {}. You can use this -
this.state.classes.map(class => <div>one class</div>)
You should try returning from the map like this:
renderClasses () {
if (!this.state.classes.length) {
console.log(this.state.userType)
if (this.state.userType) return(<div>Add Class</div>)
else return (<div>Join Class</div>)
} else {
return (<div>{
this.state.classes.map((class, index) => {
return (<div key={index}>one {class}</div>)
})
}</div>)
}
}
render() {
if (!this.state.isLogged) {
return <Redirect to='/' />
}
return (
<div>
{
this.renderClasses()
}
</div>
);
}
Everything works fine, but I have this warning Expected to return a value at the end of arrow function array-callback-return. I tried using forEach instead of map, but then <CommentItem /> doesn't even show. How do I fix this?
return this.props.comments.map((comment) => {
if (comment.hasComments === true) {
return (
<div key={comment.id}>
<CommentItem className="MainComment"/>
{this.props.comments.map(commentReply => {
if (commentReply.replyTo === comment.id) {
return (
<CommentItem className="SubComment"/>
) // return
} // if-statement
}) // map-function
} // map-function __begin
</div> // comment.id
) // return
A map() creates an array, so a return is expected for all code paths (if/elses).
If you don't want an array or to return data, use forEach instead.
The warning indicates that you're not returning something at the end of your map arrow function in every case.
A better approach to what you're trying to accomplish is first using a .filter and then a .map, like this:
this.props.comments
.filter(commentReply => commentReply.replyTo === comment.id)
.map((commentReply, idx) => <CommentItem key={idx} className="SubComment"/>);
The easiest way only if you don't need return something it'ts just return null
The problem seems to be that you are not returning something in the event that your first if-case is false.
The error you are getting states that your arrow function (comment) => { doesn't have a return statement. While it does for when your if-case is true, it does not return anything for when it's false.
return this.props.comments.map((comment) => {
if (comment.hasComments === true) {
return (
<div key={comment.id}>
<CommentItem className="MainComment" />
{this.props.comments.map(commentReply => {
if (commentReply.replyTo === comment.id) {
return (
<CommentItem className="SubComment"/>
)
}
})
}
</div>
)
} else {
//return something here.
}
});
edit you should take a look at Kris' answer for how to better implement what you are trying to do.
The most upvoted answer, from Kris Selbekk, it is totally right. It is important to highlight though that it takes a functional approach, you will be looping through the this.props.comments array twice, the second time(looping) it will most probable skip a few elements that where filtered, but in case no comment was filtered you will loop through the whole array twice. If performance is not a concern in you project that is totally fine. In case performance is important a guard clause would be more appropriated as you would loop the array only once:
return this.props.comments.map((comment) => {
if (!comment.hasComments) return null;
return (
<div key={comment.id}>
<CommentItem className="MainComment"/>
{this.props.comments.map(commentReply => {
if (commentReply.replyTo !== comment.id) return null;
return <CommentItem className="SubComment"/>
})}
</div>
)
}
The main reason I'm pointing this out is because as a Junior Developer I did a lot of those mistakes(like looping the same array multiple times), so I thought i was worth mention it here.
PS: I would refactor your react component even more, as I'm not in favour of heavy logic in the html part of a JSX, but that is out of the topic of this question.
You can use the for loop like so:
for(let i = 0 ; i < comments.length; i++){
if(comments[i].hasComments === true){
return (
<div key={comments[i].id}>
//content Here
</div> // comment.id
)
}
}
class Blog extends Component{
render(){
const posts1 = this.props.posts;
//console.log(posts)
const sidebar = (
<ul>
{posts1.map((post) => {
//Must use return to avoid this error.
return(
<li key={post.id}>
{post.title} - {post.content}
</li>
)
})
}
</ul>
);
const maincontent = this.props.posts.map((post) => {
return(
<div key={post.id}>
<h3>{post.title}</h3>
<p>{post.content}</p>
</div>
)
})
return(
<div>{sidebar}<hr/>{maincontent}</div>
);
}
}
const posts = [
{id: 1, title: 'Hello World', content: 'Welcome to learning React!'},
{id: 2, title: 'Installation', content: 'You can install React from npm.'}
];
ReactDOM.render(
<Blog posts={posts} />,
document.getElementById('root')
);
Is there anything wrong with my code below?
render(){
return (
var users= this.state.users.map(user =>
<li key={user.id}>user.name</li>
)
<ul>{users}</ul>
)
}
I get error: unexpected token.
render() should return only a single element:
render(){
return (
<ul>
{
this.state.users.map(user => (
<li key={user.id}>{user.name}</li>
)
}
</ul>
);
}
It is not clear what you're returning in your code. Either do all logic above your return call, as shown below, or do like Ori Drori does in their answer.
render() {
var users= this.state.users.map(user =>
<li key={user.id}>{user.name}</li>
);
return <ul>{users}</ul>;
}
}