How to loop over a number in React inside JSX - javascript

I need to be able to loop over a number and return some jsx. For example
<ul>
{for(i =0; i < 10; i++){
return <li>{i}</li>
}}
</ul>
This is not exactly what I want to do, but if I can solve this then I should be able to complete what I need to do. This however returns expression expected on the for. I have done some research and people say you can't use for loops inside of jsx because they do not return anything.
How do I go about looping over a number to return some amount of jsx?

You could use Array.from() instead.
let App = () => {
return <ul>{Array.from(Array(10), (e, i) => {
return <li key={i}>{i}</li>
})}</ul>
}
ReactDOM.render(
<App />,
document.getElementById('app')
);
<script src="https://unpkg.com/react#16.1.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16.1.0/umd/react-dom.development.js"></script>
<div id="app"></div>
You can also use ES6 spread syntax with map() method.
let App = () => {
return <ul>{[...Array(10)].map((e, i) => {
return <li key={i}>{i}</li>
})}</ul>
}
ReactDOM.render(
<App />,
document.getElementById('app')
);
<script src="https://unpkg.com/react#16.1.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16.1.0/umd/react-dom.development.js"></script>
<div id="app"></div>

You can do it like this :
createElements(n){
var elements = [];
for(i =0; i < n; i++){
elements.push(<li>{i}</li>);
}
return elements;
}
<ul>
{this.createElements(20)}
</ul>

You need to use recursive iterators such as map, forEach, filter etc. If you really need to do something like this you can
const statelessComp = props => {
let arr = Array.apply(null, {length: 10}).map(Number.call, Number);
return (
<ul>
{arr.map(item => {
return <li>{item}</li>
})}
</ul>
)
}
edit: these are the functions you should familiarize yourself with

This is the simple way
createElements(number){
var elements = [];
for(i =0; i < number; i++){
elements.push(<div className="list-item">{i} - Some text or element</div>);
}
return elements;
}
In return statement
<div>
{this.createElements(10)}
</div>

you can use
<ul>
<li>{[...Array.from(Array(10).keys())].map((num, i) => <p key={i}>{num}</p>)}</li>
</ul>

This worked for me
https://www.codegrepper.com/code-examples/javascript/react+loop+number+of+times
const n = 8;
{[...Array(n)].map((elementInArray, index) => (
<div className="" key={index}> Whatever needs to be rendered repeatedly... </div>
)
)}

If you don't mind adding a very common and useful library, you can use lodash and map in this situation and it will be nice and clean.
import _ from "lodash";
return (
<ul>{_.range(1, 10).map(i => (<li>i</li>))}<ul>
)

Related

return the sorted array React

How can return the sorted array from method.
Here is the code i need to display the sorted array as list.it doent work when i return numbers from sortList().Why? Return numbers is not returning the array in JSX. Is not the correct place to use return statement.
function RenderList(props){
let numbers=props.number;
function sortList(){
numbers.sort();
return numbers
}
const numList=numbers.map((num)=>(
<li>{num}</li>
))
return(
<div>
<h2>Rendering List</h2>
<button onClick={sortList}>SortList</button>
<ul>{numList}</ul>
</div>
)
}
You need to store numbers array in a state, and then update the state to re-render.
function RenderList(props){
const [numbers, setNumbers] = useState(props.numbers);
function sortList(){
setNumbers(numbers.slice().sort());
}
const numList=numbers.map((num)=>(
<li>{num}</li>
))
return(
<div>
<h2>Rendering List</h2>
<button onClick={sortList}>SortList</button>
<ul>{numList}</ul>
</div>
)
}
If you really dont want to use useState then you can do something like this
const [sort, setSort] = useState(false);
<button onClick={triggerSort}>SortList</button>
const triggerSort = () => {
if (!sort) {//if you remove this check and keep only setSort(!sort) then you can get sorted and non-sorted list when clicking
setSort(!sort)
}
}
const numList= (sort ? [...numbers].sort() : numbers).map((num)=>(
<li>{num}</li>
))
here is the demo
and if you think the sorting is some complex thing to do in each render, use the useMemo, so sorting will call only when sort gets change.
const numbersList = useMemo(() => {
return sort ? [...numbers].sort() : numbers
}, [sort]);
.....
<ul>
{
numbersList.map(num => <li>{num}</li>)
}
</ul>
demo

How to map over arrays of arrays in JSX

I have a list of names as an array. These names are then paired, into an array in my App.js
I'm looking to map over these to create a <ul> containing <li>s and I'm stuck, any help would be amazing, thanks!
Unfortunately regular map over an array like this won't work... Thanks so!
return (
<ul>
{pairs.map(pair => (
<li key={pair}>{pair}</li>
))}
</ul>
);
<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>
createPairs() {
const list = [...this.state.list];
list.sort(() => 0.5 - Math.random());
const pairs = [];
while (list.length >= 2) {
const pair = [list.pop(), list.pop()];
pairs.push(pair);
}
this.setState({
pairs
});
}
You can potentially use destructuring within your map arguments to extract the components of each pair. Remember to wrap the destructured arguments in parentheses.
return (
<ul>
{pairs.map(([pair_1, pair_2]) => (
<li key={pair_1}>{pair_1}</li>
))}
</ul>
);

Render elements with a wrapper from a map function in react

I have a react component that I need to render a bunch of elements based on the items in an array. I've setup a function to render over all of them in the array and it works nicely. Now I want to split the rendered elements into two different wrapper elements. I tried a few ways of doing this using if statements and switches but my code was getting really messy. I wanted to see if there is a cleaner way to do this, that someone might know.
renderSplit(key) {
return <div className={`inner_${key}`} key={key}>{`inner_${key}`}</div>;
}
render() {
const { arr } = this.props;
return (
<div>
{arr.map(this.renderSplit)}
</div>
);
}
So if I have an array of 5 items I want the first 4 that get rendered by renderSplit to be wrapped in a container
<div className='left'>.....</div> and the last item in the array to be wrapped in another wrapper <div className='right'>....</div>
If there is only one item, in the array it doesn't get wrapped by any wrapper div.
It should be arr.map not body.map next comes pass in the array . Then invoke the function
do this:
renderSplit(arr) {
return arr.map((entry,index)=>
<div className={`inner_${entry}`} key={entry}>{`inner_${entry}`}</div>;
)
}
render() {
const { arr } = this.props;
return (
<div>
{this.renderSplit(arr)}
</div>
);
}
you can input a condition(with respect to the index) inside the map statement , to satisfy the last statement
you can use destructuring assignment to extract the first elements and the last one from the array, check if the last one exists, if it doesn't, that means the array has only one entry, and render accordingly :
renderSplit(key) {
return <div className={`inner_${key}`} key={key}>{`inner_${key}`}</div>;
}
render() {
const { arr } = this.props;
const [last, ...firstElems ] = arr.reverse(); // reverse the array to get the last element and use the spread operator to get the rest.
return (
firstElems.length > 0 // if you have elements in the firstElems array
? (
<div className="wrapper">
<div className="left">{firstElems.reverse().map(this.renderSplit)}</div> // reverse the firstElems array to display it in the right order.
<div className="right">{this.renderSplit(last)}</div> // render the last element.
</div>
)
// other wise, render the single element you have.
: <div className="singleElement">{this.renderSplit(last)}</div>
);
}
Let's see:
renderSplit(key) {
return <div className={`inner_${key}`} key={key}>{`inner_${key}`}</div>;
}
render() {
const { arr } = this.props;
if(!arr || !arr.length) { return null; }
if(arr.length === 1) { return renderSplit(arr[0]); }
const left = arr.slice(0, arr.length - 2);
const right = arr[arr.length -1];
// Or else:
// const rightElement = arr.pop(); const leftElements = arr;
return (
// or <React.Fragment>
<>
<div className="left">
{leftElements.map(this.renderSplit)}
</div>
<div className="right">
{this.renderSplit(rightElement)}
</div>
</>
);
}

Outputting n instances of a React component

I want to create n instances of a React component.
What is a good terse way to do this give that JSX can only contain expressions?
I currently am trying the following:
<Wrapper>
{repeat(n)(i => <MyComponent i={i} />}
</Wrapper>
function repeat(n) {
return cb => Array(n).fill(null).forEach((_, i) => cb(i));
}
You can use as much JavaScript als you like :)
render() {
const lst = [1, 2, 3, 4];
return (
<div>
{lst.map(itm => <span key={itm}>{itm}</span>)}
</div>
);
}
If you do not have a key ready, you can use the second argument of the map callback which is the index in the array. More info on MDN.
In your specific case where you do not have an array but just a number:
render() {
var times = [];
for (let i = 0; i < 10; i++) {
times.push(<MyComponent key={i} i={i} />);
}
return <Wrapper>{times}</Wrapper>;
}
Also check this answer on how to use for loops. It's not quite as nice but it also works. I believe the React team has planned to make working with arrays in JSX more straight forward.
If you have just a number, and do not want to use a for loop, you could also "fake" it, for example by using string.repeat. Not sure if this is very readable though :)
render() {
return (
<div>
{'a'.repeat(10).split('').map((_, i) => <MyComponent i={i} />}
</div>
);
}

How to loop and render elements in React.js without an array of objects to map?

I'm trying to convert a jQuery component to React.js and one of the things I'm having difficulty with is rendering n number of elements based on a for loop.
I understand this is not possible, or recommended and that where an array exists in the model it makes complete sense to use map. That's fine, but what about when you do not have an array? Instead you have numeric value which equates to a given number of elements to render, then what should you do?
Here's my example, I want to prefix a element with an arbitrary number of span tags based on it's hierarchical level. So at level 3, I want 3 span tags before the text element.
In javascript:
for (var i = 0; i < level; i++) {
$el.append('<span class="indent"></span>');
}
$el.append('Some text value');
I can't seem to get this, or anything similar to work in a JSX React.js component. Instead I had to do the following, first building a temp array to the correct length and then looping the array.
React.js
render: function() {
var tmp = [];
for (var i = 0; i < this.props.level; i++) {
tmp.push(i);
}
var indents = tmp.map(function (i) {
return (
<span className='indent'></span>
);
});
return (
...
{indents}
"Some text value"
...
);
}
Surely this can't be the best, or only way to achieve this? What am I missing?
Updated: As of React > 0.16
Render method does not necessarily have to return a single element. An array can also be returned.
var indents = [];
for (var i = 0; i < this.props.level; i++) {
indents.push(<span className='indent' key={i}></span>);
}
return indents;
OR
return this.props.level.map((item, index) => (
<span className="indent" key={index}>
{index}
</span>
));
Docs here explaining about JSX children
OLD:
You can use one loop instead
var indents = [];
for (var i = 0; i < this.props.level; i++) {
indents.push(<span className='indent' key={i}></span>);
}
return (
<div>
{indents}
"Some text value"
</div>
);
You can also use .map and fancy es6
return (
<div>
{this.props.level.map((item, index) => (
<span className='indent' key={index} />
))}
"Some text value"
</div>
);
Also, you have to wrap the return value in a container. I used div in the above example
As the docs say here
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.
Here is more functional example with some ES6 features:
'use strict';
const React = require('react');
function renderArticles(articles) {
if (articles.length > 0) {
return articles.map((article, index) => (
<Article key={index} article={article} />
));
}
else return [];
}
const Article = ({article}) => {
return (
<article key={article.id}>
<a href={article.link}>{article.title}</a>
<p>{article.description}</p>
</article>
);
};
const Articles = React.createClass({
render() {
const articles = renderArticles(this.props.articles);
return (
<section>
{ articles }
</section>
);
}
});
module.exports = Articles;
Array.from() takes an iterable object to convert to an array and an optional map function. You could create an object with a .length property as follows:
return Array.from({length: this.props.level}, (item, index) =>
<span className="indent" key={index}></span>
);
I'm using Object.keys(chars).map(...) to loop in render
// chars = {a:true, b:false, ..., z:false}
render() {
return (
<div>
{chars && Object.keys(chars).map(function(char, idx) {
return <span key={idx}>{char}</span>;
}.bind(this))}
"Some text value"
</div>
);
}
You can still use map if you can afford to create a makeshift array:
{
new Array(this.props.level).fill(0).map((_, index) => (
<span className='indent' key={index}></span>
))
}
This works because new Array(n).fill(x) creates an array of size n filled with x, which can then aid map.
I think this is the easiest way to loop in react js
<ul>
{yourarray.map((item)=><li>{item}</li>)}
</ul>

Categories