Return multiple React elements in a method without a wrapper element
It's not currently possible to do this without some sort of workaround like wrapping everything in another component, since it ends up with the underlying React code trying to return multiple objects.
See this active Github issue where support for this is being considered for a future version though.
Edit: You can now do this with Fragments in React 16, see: https://reactjs.org/blog/2017/11/28/react-v16.2.0-fragment-support.html
The error message tells you exactly how to solve this:
Each child in an array or iterator should have a unique "key" prop.
Instead of this:
return [
' by ',
<a href={getAuthorUrl(this.props.author)}>{this.props.author}</a>,
];
Do this:
return [
<span key="by"> by </span>,
<a key="author" href={getAuthorUrl(this.props.author)}>{this.props.author}</a>,
];
Yes, you need to wrap the text node ("by") in a span in order to give it a key. Such are the breaks. As you can see, I've just given each element a static key
, since there's nothing dynamic about them. You could just as well use key="1"
and key="2"
if you wanted.
Alternatively, you could do this:
return <span> by <a href={getAuthorUrl(this.props.author)}>{this.props.author}</a></span>;
...which obviates the need for key
s.
Here's the former solution in a working snippet:
const getAuthorUrl = author => `/${author.toLowerCase()}`;
class Foo extends React.Component {
_renderAuthor() {
if (!this.props.author) {
return null;
}
return [
<span key="by"> by </span>,
<a key="author" href={getAuthorUrl(this.props.author)}>{this.props.author}</a>,
];
}
render() {
return (
<div>
{this.props.datePosted}
{this._renderAuthor()}
</div>
);
}
}
ReactDOM.render(<Foo datePosted="Today" author="Me"/>, document.getElementById('container'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="container"></div>
Support has been added using the Fragment component. This is a first-class component.
So you can now use:
render() {
return (
<React.Fragment>
<ChildA />
<ChildB />
<ChildC />
</React.Fragment>
);
}
For more information visit: https://reactjs.org/blog/2017/11/28/react-v16.2.0-fragment-support.html
There is another way to solve this. I will suggest you create another component Author.js:
function Author(props) {
return (<span>
<span> by </span>
<a href={props.getAuthorUrl(props.author)}>{props.author}</a>
</span>)
}
class Foo extends React.Component {
render() {
return (
<div>
{this.props.title}
{this.props.author && <Author author={this.props.author} getAuthorUrl={this.getAuthorUrl} />}
</div>
);
}
}
I didn't test this code though. But it will look more cleaner I think. Hope it helps.