Ad

React JSX Conditional Wrapper For Bootstrap Grid

- 1 answer

Just face this funny thing while rendering React components with Bootstrap grid, assuming I need to render two col-md-6 in a row, each <Book />component is put inside a col-md-6div block

+---------------------+
| col-md-6 | col-md-6 |
| Book     | Book     |  <--- row
|---------------------|
| col-md-6 | col-md-6 |
| Book     | Book     |  <--- row
+---------------------+

and it expects to form similar to the below structure,

<Row>
    <Col>
        <Book />
    </Col>
    <Col>
        <Book />
    </Col>
</Row>
<Row>
    <Col>
        <Book />
    </Col>
    <Col>
        <Book />
    </Col>
</Row>

What I tried to render like following,

export default class BookList extends React.Component {
    render() {
        let books = [];
        lodash.each(this.props.books, function (book, index) {
            index % 2 === 0 ? books.push(<div className="row" key={index}>): null;
            books.push(
                    <div className="col-md-6">
                        <Book />
                    </div>
            )
            index % 2 === 1 || index === this.props.books.length - 1? books.push(</div>): null
        })

        return (
            <div className="container">
                {books}
            </div>
        )
    }
}

But the output is a malformed HTML, it looks like JSX validate each item on render, and not wait for closing tag.

Is there any way or tip to make it work correctly?

Ad

Answer

You've treated the JSX as strings instead of XML, and when it was compiled to JS, it was invalid.

React works well with small components, so break the BooksContainer into pairs and render the BooksRows, and the BooksRows will render the books (fiddle - inspect the result):

code:

const Book = ({ book }) => (
  <div className="col-md-6">
    { book.name }
  </div>
);

const BooksRow = ({ bookPair }) => (
  <div className="row">
    {
      bookPair.map((book, index) => (
        <Book key={ index } book={ book }/>
      ))
    }
  </div>
);

const BooksContainer = ({ books }) => (
  <div className="container">
    {
      books.reduce((pairs, book, index) => { // split the books into pairs
        if(index % 2 === 0) {
           pairs.push([]);
        }
        pairs[pairs.length - 1].push(book);
        return pairs;
      }, []).map((pair, index) => ( // map the pairs to row
        <BooksRow key={ index } bookPair={ pair } />
      ))
    }
  </div>
);

const books = [
  {
    name: 'cats'
  },
  {
    name: 'dogs'
  },
  {
    name: 'rabbits'
  },
  {
    name: 'elephents'
  },
  {
    name: 'snails'
  },
  {
    name: 'tigers'
  }
];

ReactDOM.render(
  <BooksContainer books={ bon  },
  {
    name: 'tigers'
  }
];

ReactDOM.render(
  <BooksContainer books={ books } />,
  document.getElementById('container')
);
Ad
source: stackoverflow.com
Ad