76

I know JSX can be very misleading because it looks like strings and it is not, thus the "string" term in the question, even if we are not really manipulating strings.

Here is a code example (wrong, obviously):

let line = <Line key={line.client_id} line={line}/>;
if(line.created_at) {
    return <div className="date-line"><strong>{line.created_at}</strong></div> + line;
} else {
    return chat_line;
}

I have a line, and I want to "concatenate" some divs in front of it under certain conditions. What would be the proper syntax? I've tried parenthesis, brackets, plus sign... None of them seem to work...

thanks

revelt
  • 2,312
  • 1
  • 25
  • 37
Sephy
  • 50,022
  • 30
  • 123
  • 131

5 Answers5

103

Use arrays:

let lineComponent = <Line key={line.client_id} line={line}/>;
if (line.created_at) {
  return [
    <div key="date" className="date-line"><strong>{line.created_at}</strong></div>,
    lineComponent,
  ];
} else {
  return chat_line;
}

Or use fragments:

import createFragment from "react-addons-create-fragment";

let lineComponent = <Line key={line.client_id} line={line}/>;
if (line.created_at) {
  return createFragment({
    date: <div className="date-line"><strong>{line.created_at}</strong></div>,
    lineComponent: lineComponent,
  });
} else {
  return chat_line;
}

In both cases, you have to provide keys for React. In case of array, you set key directly on element. Regarding fragments, you provide key:element pairs.

NOTE: When returning from render method, you can only return single element, or NULL. Examples provided are invalid in that case.

Andreyco
  • 22,476
  • 5
  • 61
  • 65
  • yep, indeed the array technique is working. That's a bit weird at first, but at least, you can format it line by line to have something looking like HTML. Quite neat. Thx ! – Sephy Apr 28 '16 at 12:15
  • 1
    in real world usage, I prefer fragments. Just a personal preference :) – Andreyco Apr 28 '16 at 13:10
  • Good to know is that using the Array method will force you to have the unique key attribute. – Manel Nov 13 '19 at 10:06
20

For React Native, I prefer this technique:

  1. pro: in contrast to the array technique you don't have to artificially create keys
  2. con: requires the overhead of a containing element (e.g., View, below)
jsx = <Text>first</Text>;
jsx = <View>{jsx}<Text>second</Text></View>;
Pete Alvin
  • 4,646
  • 9
  • 39
  • 56
16

You can use empty tags, I mean, <> and </>, whenever you just don't want any additional Container-Element (e.g. <View>), like below:

  render() {
    return (
      <>
        <Text>First</Text>

        <Text>Second</Text>
      </>
    );
  }

Example:

import React from 'react'
import { View, Text } from 'react-native'

import Reinput from 'reinput'

export default class ReinputWithHeader extends Reinput {
  constructor(props) {
    super(props);
  }
  render() {
    return (
      <>
        <View style={{backgroundColor: 'blue', flexDirection: 'row', alignSelf: 'stretch', height: 20}}>
          <Text>Blue Header</Text>
        </View>

        {super.render()}
      </>
    );
  }
}

Note: I tested and it works on react-native too; see also Fragments.

Preview:

enter image description here

Top-Master
  • 7,611
  • 5
  • 39
  • 71
11

It is possible to use an Array and push jsx code there. For example:

   function App() {

      function cells() {
        const size = 10;
        const cells = [];
        for (let i=0; i<size; i++) {
          cells.push(
            <tr>
              <td>Hello World</td>
            </tr>
          )
        }
        return cells;
      }

      return (
        <table>
          <tbody>
            {cells()}
          </tbody>
        </table>
      );
    }
weivall
  • 917
  • 13
  • 16
1

If you are okay using a parent object such as another div you can also do it this way:

let line = <Line key={line.client_id} line={line}/>;
if(line.created_at) {
    return <div><div className="date-line"><strong>{line.created_at}</strong></div>{line}</div>;
} else {
    return chat_line;
}
kojow7
  • 10,308
  • 17
  • 80
  • 135