2

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?

5
  • Not sure what you are trying to do. But you should be able to use either JavaScript Conditional Operator or Logical && Operator. Commented Aug 14, 2017 at 1:13
  • Use if() statments also throws an error within the render loop 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 Commented Aug 14, 2017 at 1:25
  • Perhaps this fiddle is better, without the extra element Commented Aug 14, 2017 at 2:07
  • How is this work index % 2: <h1>Test Output/h1>? Commented Aug 14, 2017 at 3:12

2 Answers 2

5

First, 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 components, 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 composed 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.com/wohima/edit?js,output

Sign up to request clarification or add additional context in comments.

8 Comments

so you can return an array of elements?
@JaromandaX you can indeed, and if you think about it, this is what items.map(...) is doing whenever you use it. With one caveat!!! You can't return an array from a component's render method (yet). But any other function is allowed to return an array of JSX elements.
indeed, I did just realise that of course .map is returning an array! The reactjs documentation confused me :p wouldn't jsfiddle.net/uxd6Lxkk/2 be closer to the OP's intent?
@JaromandaX null values won't be rendered by React, so no need to filter them out. However, your example brings up an important issue: if you return an array on each iteration of .map(...), React will complain if you don't assign each element a unique key. If you use index for both the span and the h1 (in your example), only the span will ever render. React will throw a flattenChildren error and flatten the elements with identical keys, throwing out the other one. I may edit the answer to talk more about the importance of keys...
I'm not using index any differently to your code, not sure why you think index has special meaning in my fiddle compared to your answer - maybe flattening the result of .map would help? jsfiddle.net/uxd6Lxkk/4
|
0

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.

5 Comments

you need a : if you use ?
It still get this error: Module build failed: SyntaxError: Unexpected token, expected , (73:11) 71 | <span dangerouslySetInnerHTML={{ __html: item }}></span> 72 | > 73 | {index % 2 == 0 && ( | ^ 74 | <h1>Test Output/h1> 75 | )}
@DevinDixon I have edited the answer. You need to have && instead of ?
I have... it appears using inter brackets {} has issues
as I said in question comment, return value of items.map needs to be a single element, not two

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.