score:207
A simple solution is to use reduce()
without second argument and without spreading the previous result:
class List extends React.Component {
render() {
<div>
{this.props.data
.map(t => <span>{t}</span>)
.reduce((prev, curr) => [prev, ', ', curr])}
</div>
}
}
Without second argument, reduce()
will start at index 1 instead of 0, and React is perfectly happy with nested arrays.
As said in the comments, you want to only use this for arrays with at least one item, because reduce()
without second argument will throw with an empty array. Normally this should not be a problem, since you want to display a custom message saying something like 'this is empty' for empty arrays anyway.
Update for Typescript
You can use this in Typescript (without type-unsafe any
) with a React.ReactNode
type parameter on .map()
:
class List extends React.Component {
render() {
<div>
{this.props.data
.map<React.ReactNode>(t => <span>{t}</span>)
.reduce((prev, curr) => [prev, ', ', curr])}
</div>
}
}
score:-2
As of React 17, you can simply:
<div>
{[1, 2, 3].map((e, i) => <p key={i}>{e}</p>)}
</div>
And it will render as:
<div>
<p>1</p>
<p>2</p>
<p>3</p>
</div>
score:-1
Simply add join() after map and put it inside tag:
<span>{this.props.data.map((item) => item).join(', ')}</span>
score:-1
{errors.username.map((e,k) => <span key={k}>{e} <br/></span>)}
easiest way i could find.
score:0
This worked for me:
{data.map( ( item, i ) => {
return (
<span key={i}>{item.propery}</span>
)
} ).reduce( ( prev, curr ) => [ prev, ', ', curr ] )}
score:0
As mentioned by Pith, React 16 allow you to use strings directly so wrapping the strings in span tags are no longer needed. Building on Maarten's answer, if you also want to deal with a custom message right away (and avoid throwing an error on empty array), you could lead the operation with a ternary if statement on the length property on the array. That could look something like this:
class List extends React.Component {
const { data } = this.props;
render() {
<div>
{data.length
? data.reduce((prev, curr) => [prev, ', ', curr])
: 'No data in the array'
}
</div>
}
}
score:0
This should return a flat array. Handle s case with non iterable first object by providing an initial empty array and filters the not needed first comma from the outcome
[{}, 'b', 'c'].reduce((prev, curr) => [...prev, ', ', curr], []).splice(1) // => [{}, 'b', 'c']
score:0
Am I the only who thinks there's a lot of needless spreading and nesting going on in the answers here? Points for being concise, sure, but it leaves the door open to issues of scale or React changing how they deal with nested arrays/Fragments.
const joinJsxArray = (arr, joinWith) => {
if (!arr || arr.length < 2) { return arr; }
const out = [arr[0]];
for (let i = 1; i < arr.length; i += 1) {
out.push(joinWith, arr[i]);
}
return out;
};
// render()
<div>
{joinJsxArray(this.props.data.map(t => <span>t</span>), ', ')}
</div>
One array, no nesting. No sexy method chaining either, but if you find yourself doing this often you can always add it to the array prototype or wrap it in a function that takes a mapping callback as well to do it all in one go.
score:0
function YourComponent(props) {
const criteria = [];
if (something) {
criteria.push(<strong>{ something }</strong>);
}
// join the jsx elements with `, `
const elements = criteria.reduce((accu, elem) => {
return accu === null ? [elem] : [...accu, ', ', elem]
}, null);
// render in a jsx friendly way
return elements.map((el, index) => <React.Fragment key={ index }>{ el }</React.Fragment> );
}
score:0
With flatMap
(supported in all mainstream modern browsers as of June 2022), you can do it in a single step, something like this:
const Demo = ({ data }) => <div>{data.flatMap(
(t, i) => [...(i ? [', '] : []), <span key={i}>{t}</span>]
)}</div>
ReactDOM.render(<Demo data={['tom', 'jason', 'chris']} />, document.body)
body { font-family: sans-serif; }
span { color: firebrick; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
If index == 0, the callback returns [span]
; else, it returns [text, span]
. Because we used flatMap
instead of map
, the resulting 2d array of [[span], [text, span], [text, span]]
is flattened to [span, text, span, text, span]
, which React can render.
score:1
Use nested array to keep "," outside.
<div>
{this.props.data.map((element, index) => index == this.props.data.length - 1 ? <span key={index}>{element}</span> : [<span key={index}>{element}</span>, ", "])}
</div>
Optimize it by saving the data to array and modify last element instead of checking if its last element all the time.
let processedData = this.props.data.map((element, index) => [<span key={index}>{element}</span>, ", "])
processedData [this.props.data.length - 1].pop()
<div>
{processedData}
</div>
score:3
Using es6 you could do something like:
const joinComponents = (accumulator, current) => [
...accumulator,
accumulator.length ? ', ' : '',
current
]
And then run:
listComponents
.map(item => <span key={item.id}> {item.t} </span>)
.reduce(joinComponents, [])
score:6
My variant:
{this.props.data
.map(item => <span>{item}</span>)
.map((item, index) => [index > 0 && ', ', item ])}
score:9
the <span>{t}</span>
you are returning is an object, not a string. Check the react docs about it https://facebook.github.io/react/docs/jsx-in-depth.html#the-transform
By using .join()
on the returned array from map
, you are joining the array of objects. [object Object], ...
You can put the comma inside the <span></span>
so it gets rendered the way you want it to.
render() {
return (
<div>
{ this.props.data.map(
(t,i) => <span>{t}{ this.props.data.length - 1 === i ? '' : ','} </span>
)
}
</div>
)
}
score:11
The accepted answer actually returns an array of arrays because prev
will be an array each time. React is smart enough to make this work, but is it is prone to causing problems in the future such as breaking Reacts diffing algorithm when giving keys to each result of map.
The new React.Fragment
feature lets us do this in an easy to understand manner without the underlying issues.
class List extends React.Component {
render() {
<div>
{this.props.data
.map((t, index) =>
<React.Fragment key={index}>
<span> {t}</span> ,
</React.Fragment>
)
</div>
}
}
With React.Fragment
we can simply place the separator ,
outside of the of the returned HTML and React won't complain.
score:19
If I just want to render a comma-separated array of components, I usually find reduce
too verbose. A shorter solution in such cases is
{arr.map((item, index) => (
<Fragment key={item.id}>
{index > 0 && ', '}
<Item {...item} />
</Fragment>
))}
{index > 0 && ', '}
will render a comma followed by a space in front of all array items except the first one.
If you want to separate the second-to-last item and the last one by something else, say the string ' and '
, you can replace {index > 0 && ', '}
with
{index > 0 && index !== arr.length - 1 && ', '}
{index === arr.length - 1 && ' and '}
score:22
Update with React 16: It's now possible to render strings directly, so you can simplify your code by removing all the useless <span>
tags.
const list = ({ data }) => data.reduce((prev, curr) => [ prev, ', ', curr ]);
score:32
You can use reduce
to combine multiple elements of an array:
React.createClass({
render() {
<div>
this.props.data
.map(t => <span>t</span>)
.reduce((accu, elem) => {
return accu === null ? [elem] : [...accu, ',', elem]
}, null)
</div>
}
})
This initializes the accumulator with null, so we can wrap the first item in an array. For each following element in the array, we construct a new array that contains all previous elements using the ...-operator
, add the separator and then the next element.
Source: stackoverflow.com
Related Query
- How to render react components by using map and join?
- How to dynamically and conditionally render select options inside of a map function using React Hooks
- How to add an image in the first react component and ignore in rest of the components using map function
- When we render react Components from an iterable using Array.prototype.map() how is the index generated, and how does react uses it?
- How to render and map an object using a variable as a key in react
- How to import and export components using React + ES6 + webpack?
- Using for loops and switch cases in React to dynamically render different components
- How to render images with React JS using map or loop?
- How to intercept back button in a React SPA using function components and React Router v5
- How can show and hide react components using hooks
- How to add a legend to the map using react leaflet, without using refs and manually modifying the DOM?
- How to draw a bubble map with longitude and latitude using Highcharts in react
- How can I conditionally render elements with React and Firebase via map function?
- How to bundle ES6 based React components and keep the bundle in ES6, using webpack?
- How to map over 2 Array of object in React and render to Table
- How to render jsx only when a condition is true using react and typescript?
- How to avoid re-renders in React when using conditional Render and children node prop
- how do I render a page in react using functional components when onSubmit?
- How to parse Embeddable Links from Markdown and render custom React Components
- How to use the useHook in the component rather than passing the value returned from it as a prop to the components using react and typescript?
- How can I render markers on a map in React using a for loop?
- How to dynamically render Route components in React-router-dom and React
- How do I properly render React components using conditionals if I need to show custom prompt first?
- How Use images from javascript array in react using filter and map function
- How to render output from react-html-email using React and Webpack
- Using React components to edit objects and render said changes?
- How do I map over an array of objects in React and then conditionally render a component based on a previous value?
- How to render a child component within parent component using react and typescript?
- How to render the parent component in the child component using react and typescript?
- How to efficiently add variants for components using styled-components and React
More Query from same tag
- Import multiple images on React
- Dynamic import images from folders
- Identifying React component in reducer?
- Uncaught Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object
- state value is undefined on Redirect
- How to prevent react re-rendering images that are coming from an url?
- add props to route component
- Setting hovered style for material-ui IconButton
- Need to remove underline on hover and on focus MUI TimePicker
- Can not pass on property from one Component to another
- React - onSelect function not working of react bootstrap
- How to add icone in 'svg' format to SweetAlert for Bootstrap?
- How to pass selected items data to another component React
- How can I return my data string through a dangerouslyHTML function in order to render out bold tags?
- How to pass function as props in React?
- Is it possible to render an image stored in laravel storage while in development mode?
- Modal only shows last element of mapped array in React
- How do you pass in a property when instantiating a React component
- getDisplayMedia() not working correctly on Android device
- How to fire a click event in a ul, li or div in reactjs
- State hooks does not update state parameters on redux store update
- The element onClick handler conflicts with form onSubmit of sibling element
- Routes are not working in react when I am using in given format
- Handler function doesn't have access to updated state variable
- Invariant Violation: You should not use <Switch> outside a <Router>
- State changes during useFocus cleanup
- Infinite loop for a protected route
- How can i use breakpoint.value
- How to cache a React app with service workers
- Javascript (React + Flow) - Destructuring with nullable nested objects