In ReactJS, I am trying to call an if statement within a map loop. An example code is this:
var items = ['abc', '123', 'doe', 'rae', 'me'];
return (
<div>
{items.map((item, index) => (
<span dangerouslySetInnerHTML={{ __html: item }}></span>
{index % 2:
<h1>Test Output/h1>
}
))}
</div>
}
Except I keep getting his error:
Module build failed: SyntaxError: Unexpected token, expected , (73:11)
web_1 |
web_1 | 71 | <span dangerouslySetInnerHTML={{ __html: item }}></span>
web_1 | 72 |
web_1 | > 73 | {index % 2:
web_1 | | ^
How can I call an if statement within a loop?
In ReactJS, I am trying to call an if statement within a map loop. An example code is this:
var items = ['abc', '123', 'doe', 'rae', 'me'];
return (
<div>
{items.map((item, index) => (
<span dangerouslySetInnerHTML={{ __html: item }}></span>
{index % 2:
<h1>Test Output/h1>
}
))}
</div>
}
Except I keep getting his error:
Module build failed: SyntaxError: Unexpected token, expected , (73:11)
web_1 |
web_1 | 71 | <span dangerouslySetInnerHTML={{ __html: item }}></span>
web_1 | 72 |
web_1 | > 73 | {index % 2:
web_1 | | ^
How can I call an if statement within a loop?
Share Improve this question asked Aug 14, 2017 at 1:03 Devin DixonDevin Dixon 12.5k24 gold badges97 silver badges179 bronze badges 5- Not sure what you are trying to do. But you should be able to use either JavaScript Conditional Operator or Logical && Operator. – Tharaka Wijebandara Commented Aug 14, 2017 at 1:13
- Use if() statments also throws an error within the render loop – Devin Dixon Commented Aug 14, 2017 at 1:20
- this fiddle does what you want, except the span + (optinal) h1 are inside another span - probably not what you want - I don't know react very well, but it seems that the result of .map needs to return a single element, not (potentially) two elements – Jaromanda X Commented Aug 14, 2017 at 1:25
- Perhaps this fiddle is better, without the extra element – Jaromanda X Commented Aug 14, 2017 at 2:07
- How is this work index % 2: <h1>Test Output/h1>? – Andrii Starusiev Commented Aug 14, 2017 at 3:12
2 Answers
Reset to default 5First, you can't return multiple sibling elements as JSX without a parent container, unless you put them into an array (though you can't return arrays from render
methods until React adds support for returning fragments).
This is invalid:
return (
<div>First sibling</div>
<div>Second sibling</div>
);
These are both valid:
return (
<div>
<div>First sibling</div>
<div>Second sibling</div>
<div>
);
// vs.
// (notice this requires adding keys)
return ([
<div key={1}>First sibling</div>,
<div key={2}>Second sibling</div>
]);
Second, if you want to use a conditional statement to render ponents, you have to do it like this:
{(index % 2 === 0) &&
<div>This will render when index % 2 === 0</div>
}
The reason this works is that the &&
operator in JavaScript evaluates to the second operand (your JSX in this case) if the first operand is truthy. You can also use ternary statements, like this:
{(index % 2 === 0) ?
<div>This will render when index % 2 === 0</div>
:
<div>This will render when index % 2 !== 0</div>
}
Putting this all together
var items = ['abc', '123', 'doe', 'rae', 'me'];
return (
<div>
{items.map((item, index) => (
<div>
<span dangerouslySetInnerHTML={{ __html: item }}></span>
{(index % 2 === 0) &&
<h1>Test Output/h1>
}
</div>
))}
</div>
}
[Edit] Important note
I should mention that whenever you're rendering an array of elements using something like items.map(...)
, you should really be assigning a unique key to each element in the list that you're rendering:
{items.map((item, index) => (
<div key={item.get('id')}>Item #{index}</div>
))}
The reason is that React does some optimizations here to make rendering (and re-rendering) lists less costly. If it sees a list that used to be posed of keys 0, 1, 2
and you've done some operation to reorder the items in your state, so that now the keys are passed to your map function in the order 0, 2, 1
, it won't rebuild the DOM to reflect the changed order, but rather will just swap the DOM nodes (which is faster).
This leads to why you don't want to use index
as a key for your elements, UNLESS you know that their order won't change. Let's say you used the iteration index as your keys:
{items.map((item, index) => (
<div key={index}>Item #{index}</div>
))}
Now, if your items change order, they'll be output with the keys in the same order (index 0
will always be the first index, index 1
will always be the second index, and so on) but with different text inside each div. React will do a diff with the real DOM, notice that the value of each div has changed, and rebuild that entire chunk of the DOM from scratch.
This gets even worse if your list elements include something with state that isn't reflected in the DOM, like an <input>
. In that case, React will rebuild the DOM, but any text the user has input in those fields will remain exactly where it was! Here's an example from Robin Pokorny that demonstrates what can go wrong (sourced from this article):
https://jsbin./wohima/edit?js,output
I guess your condition for the if is index % 2 == 1
which shows the Heading when index
is an odd number
{index % 2 == 1 && (
<h1>Test Output/h1>
)}
Official Documentation
But in your case, you are writing this if condition within {}. That means, you are now writing the JavaScript. So, just use the JavaScript syntax.
if(index % 2 == 1){
return(
<div>
<span dangerouslySetInnerHTML={{ __html: item }}></span>
<h1>Test Output/h1>
</div>);
}
Update: As Jaromanda pointed out, you need to return one element. So, wrapping your <span>
and <h1>
into <div>
will gives a single element.