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-6
div
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?
Conditional Rendering. In React, you can create distinct components that encapsulate behavior you need. Then, you can render only some of them, depending on the state of your application. Conditional rendering in React works the same way conditions work in JavaScript.
It can be handy for conditionally including an element: It works because in JavaScript, true && expression always evaluates to expression, and false && expression always evaluates to false. Therefore, if the condition is true, the element right after && will appear in the output. If it is false, React will ignore and skip it.
The condition part is quite self-explanatory. Then the tricky part is the wrapper. It receives a function that will be called in the ConditionalWrapper component itself when the condition is true. There it will receive the implicit children as argument.
While declaring a variable and using an if statement is a fine way to conditionally render a component, sometimes you might want to use a shorter syntax. There are a few ways to inline conditions in JSX, explained below.
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={ books } />,
document.getElementById('container')
);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With