jsx complied error map within map - javascript

{!this.state.isLoading && applicants.findIndex(obj => obj.is_new) === 1 &&
<div>is new</div>
{applicants.map((obj,index) => {
if(obj.is_new){
return this.renderApplicantsList(obj, index)
}
})}
}
what's wrong with my code above? unexpected token but I can't spot any wrong in it.

A JSX element may only contain a single root. The way you are checking for isLoading and is_new is also a bit awkward, I would go for something such as:
<div>
{
!this.state.isLoading && applicants.findIndex(obj => obj.is_new) === 1 ? (
<div>
<div>is new</div>
{
applicants.map((obj,index) => {
if(obj.is_new){
return this.renderApplicantsList(obj, index)
}
})
}
</div>
) : null
}
</div>

Related

React Map Method within Map Method

I am trying to include map method in a map method while getting a list as an element from the first map method.
{columns &&
columns.map(column =>
column.list && column.list?
(column.list.map((item)=>{
return (
<CustomTableCell align="center">{item.name}
<span>{item.convertMethod(item.id, item.lists)}</span>
</CustomTableCell>
);
})):
<CustomTableCell align="center"> {column.name} </CustomTableCell>
) }
Error still exists
return (
<div className="App">
{
columns.map(column => {
return (
column.list && column.list.length > 0 ? (
column.list.map(item => {
return (
<div key={item.name}>{item.name}</div>
)
})
): ("")
)
})
}
</div>
);
demo

React: only map when props exists

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;
}
}

Write javascript commands on a render() component method

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

How do I fix "Expected to return a value at the end of arrow function" warning?

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')
);

react and conditional rendering

Currently I am using the following code to conditionally render some HTML based on hasLocations variable.
Code works, but I wish to know if there is a better way to achieve the same result, for example, I am not sure having two return is a good practice.
const Finder = ({ locations, onLocationClick }) => {
let hasLocations = locations.length > 0
if (hasLocations) {
return (
<ul>
{locations.map((location, index) =>
<Location
key={index}
{...locations[index]}
onLocationClick={() => onLocationClick(location)}
/>
)}
</ul>
)
} else {
return (null)
}
}
Alternatively you chould use conditional rendering. For your example, this would look like this.
const Finder = ({ locations, onLocationClick }) => {
return (
<ul>
{locations.length > 0 &&
locations.map((location, index) =>
<Location
key={index}
{...locations[index]}
onLocationClick={() => onLocationClick(location)}
/>
)}
</ul>
);
}
EDIT: My solution would be the following.
I would avoid adding any logic in it(AKA presentational component). So it would become
const Finder = ({ locations, onLocationClick }) => {
return (
<ul>
locations.map((location, index) =>
<Location
key={index}
{...locations[index]}
onLocationClick={() => onLocationClick(location)}
/>
)
</ul>
);
}
And when you need to use it you can do something like this:
return (
<div>
{locations.length > 0 && Finder}
</div>
);
There's nothing wrong with using multiple returns in a function, but when you do it's good practice to put a "default" return as the last statement in the function to make it more apparent that the function always returns something.
In your case that means you could move your return (null) (no need to wrap null in brackets, btw) statement out of the else clause and just put it as the last statement of the function.
It's also possible to use a single return statement with ternary in your return, like this:
return locations.length > 0 ? (
<ul>
{locations.map((location, index) =>
<Location
key={index}
{...locations[index]}
onLocationClick={() => onLocationClick(location)}
/>
)}
</ul>
) : null

Categories