How to return multiple lines JSX in another return statement in React?

How to return multiple lines JSX in another return statement in React?

Single line works fine
render: function () {
return (
{[1,2,3].map(function (n) {
return

{n}

}}
);
}

not for multiple lines
render: function () {
return (
{[1,2,3].map(function (n) {
return (

Item {n}

Description {n}

)
}}
);
}

Thanks.

Solutions/Answers:

Solution 1:

Try to think of the tags as function calls (see docs). Then the first one becomes:

{[1,2,3].map(function (n) {
  return React.DOM.p(...);
})}

And the second one:

{[1,2,3].map(function (n) {
  return (
    React.DOM.h3(...)
    React.DOM.p(...)
  )
})}

It should now be clear that the second snippet doesn’t really make sense (you can’t return more than one value in JS). You have to either wrap it in another element (most likely what you’d want, that way you can also provide a valid key property), or you can use something like this:

{[1,2,3].map(function (n) {
  return ([
    React.DOM.h3(...),
    React.DOM.p(...)
  ]);
})}

With JSX sugar:

{[1,2,3].map(function (n) {
  return ([
    <h3></h3>, // note the comma
    <p></p>
  ]);
})}

You don’t need to flatten the resulting array, React will do that for you. See the following fiddle http://jsfiddle.net/mEB2V/1/. Again: Wrapping the two elements into a div/section will most likely be better long term.

Solution 2:

It seems the old answer about returning an array no longer applies (maybe since React ~0.9, as @dogmatic69 wrote in a comment).

The docs say you need to return a single node:

Maximum Number of JSX Root Nodes

Currently, in a component’s render,
you can only return one node; if you have, say, a list of divs to
return, you must wrap your components within a div, span or any other
component.

Don’t forget that JSX compiles into regular JS; returning two
functions doesn’t really make syntactic sense. Likewise, don’t put
more than one child in a ternary.

In many cases you can simply wrap things in a <div> or a <span>.

In my case, I wanted to return multiple <tr>s. I wrapped them in a <tbody> – a table is allowed to have multiple bodies.

EDIT: As of React 16.0, returning an array is apparently allowed again, as long as each element has a key: https://facebook.github.io/react/blog/2017/09/26/react-v16.0.html#new-render-return-types-fragments-and-strings

EDIT: React 16.2 lets you surround a list of elements with <Fragment>…</Fragment> or even <>…</>, if you prefer that to an array: https://blog.jmes.tech/react-fragment-and-semantic-html/

Solution 3:

From React v16.0.0 onwards, it is possible to Return multiple elements by wrapping them within an Array

render() {
  return (
    {[1,2,3].map(function (n) {
      return [
        <h3>Item {n}</h3>.
        <p>Description {n}</p>
      ]
    }}
  );
}

Also from React v16.2.0, a new feature called React Fragments is introduced which you can use to wrap multiple elements

render() {
  return (
    {[1,2,3].map(function (n, index) {
      return (
        <React.Fragment key={index}>
            <h3>Item {n}</h3>
            <p>Description {n}</p>
        </React.Fragment>
      )
    }}
  );
}

As per the documentation:

A common pattern in React is for a component to return multiple
elements. Fragments let you group a list of children without adding
extra nodes to the DOM.

Fragments declared with the explicit syntax may have
keys. A use case for this is mapping a collection to an array of
fragments — for example, to create a description list:

function Glossary(props) {
  return (
    <dl>
      {props.items.map(item => (
        // Without the `key`, React will fire a key warning
        <React.Fragment key={item.id}>
          <dt>{item.term}</dt>
          <dd>{item.description}</dd>
        </React.Fragment>
      ))}
    </dl>
  );
}

key is the only attribute that can be passed to Fragment. In the
future, we may add support for additional attributes, such as event
handlers.

Solution 4:

Also, you might want to return several list items in some helper function inside a React component. Just return an array of html nodes with the key attribute:

import React, { Component } from 'react'

class YourComponent extends Component {
  // ...

  render() {
    return (
      <ul>
        {this.renderListItems()}
      </ul>
    )
  }      

  renderListItems() {
    return [
      <li key={1}><a href="#">Link1</a></li>,
      <li key={2}><a href="#">Link2</a></li>,
      <li key={3} className="active">Active item</li>,
    ]
  }
}

Solution 5:

You can use createFragment here.

https://facebook.github.io/react/docs/create-fragment.html

import createFragment from 'react-addons-create-fragment';
...
{[1,2,3].map((n) => createFragment({
    h: <h3>...</h3>,
    p: <p>...</p>
  })
)}

(using ES6 and JSX syntax here)

you first have to add the react-addons-create-fragment package :

npm install --save react-addons-create-fragment

Advantage over Jan Olaf Krems’s solution : react does not complain about the missing key

Solution 6:

Updated

Use React Fragment. It’s simple. Link to fragment documentation.

render() {
  return (
    <>
    {[1,2,3].map((value) => <div>{value}</div>)}
    </>
  );
}

Old answer – obsolete

With React > 16 you can use react-composite.

import { Composite } from 'react-composite';

// ...

{[1,2,3].map((n) => (
  <Composite>
    <h2>Title {n}</h2>
    <p>Description {n}</p>
  </Composite>
))};

Of course, react-composite has to be installed.

npm install react-composite --save

References

How to slide in and out from the bottom in React Native?

How to slide in and out from the bottom in React Native?

In React Native iOS, I would like to slide in and out a like to following in the picture.
In the following example, when a button is pressed, the Payment Information view pops up from the bottom and when the collapse button is pressed, it goes back down and disappears.
What would be the correct and proper way to go about doing so?

Thank you in advance!
EDIT

Solutions/Answers:

Solution 1:

Basically, you need to absolute-position your view to the bottom of the screen. Then you translate its y value to equal its height. (The sub view must have a specific height in order to know how much to move it)

Here’s a playground showing the result:
https://rnplay.org/apps/n9Gxfg

Code:

'use strict';

import React, {Component} from 'react';
import ReactNative from 'react-native';

const {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  TouchableHighlight,
  Animated
} = ReactNative;


var isHidden = true;

class AppContainer extends Component {
  constructor(props) {
    super(props);
    this.state = {
      bounceValue: new Animated.Value(100),  //This is the initial position of the subview
      buttonText: "Show Subview"
    };
  }


  _toggleSubview() {    
    this.setState({
      buttonText: !isHidden ? "Show Subview" : "Hide Subview"
    });

    var toValue = 100;

    if(isHidden) {
      toValue = 0;
    }

    //This will animate the transalteY of the subview between 0 & 100 depending on its current state
    //100 comes from the style below, which is the height of the subview.
    Animated.spring(
      this.state.bounceValue,
      {
        toValue: toValue,
        velocity: 3,
        tension: 2,
        friction: 8,
      }
    ).start();

    isHidden = !isHidden;
  }

  render() {
    return (
      <View style={styles.container}>
          <TouchableHighlight style={styles.button} onPress={()=> {this._toggleSubview()}}>
            <Text style={styles.buttonText}>{this.state.buttonText}</Text>
          </TouchableHighlight>
          <Animated.View
            style={[styles.subView,
              {transform: [{translateY: this.state.bounceValue}]}]}
          >
            <Text>This is a sub view</Text>
          </Animated.View>
      </View>
    );
  }
}

var styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
    marginTop: 66
  },
  button: {
    padding: 8,
  },
  buttonText: {
    fontSize: 17,
    color: "#007AFF"
  },
  subView: {
    position: "absolute",
    bottom: 0,
    left: 0,
    right: 0,
    backgroundColor: "#FFFFFF",
    height: 100,
  }
});

AppRegistry.registerComponent('AppContainer', () => AppContainer);

Solution 2:

I know it is a little bit late, but thought it might be useful for someone. You should try out a component called rn-sliding-out-panel. It works awesomely. https://github.com/octopitus/rn-sliding-up-panel

<SlidingUpPanel
    draggableRange={top: 1000, bottom: 0}
    showBackdrop={true|false /*For making it modal-like*/}
    ref={c => this._panel = c}
    visible={ture|false /*If you want it to be visible on load*/}
></SlidingUpPanel>

And you can even open it from an external button:

<Button onPress={()=>{this._panel.transitionTo(1000)}} title='Expand'></Button>

You can install it via npm: sudo npm install rn-sliding-out-panel --save on your react-native root directory.


I hope it helps someone 😀

References