How to map over arrays of arrays in JSX - javascript

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>
);

Related

Looping <li> elements in JSX React

In React.js documentation, I wonder how Array.map() is used in JSX React.
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
<li key={number.toString()}>
{number}
</li>
);
return (
<ul>{listItems}</ul>
);
}
in <ul> tag, why we just put the variable listItems directly?. Because I think it will return a single array instead of <li> elements like this :
<ul>
[
<li></li>,
<li></li>,
<li></li>,
]
</ul>
how does JSX treat an array?
Did I have to loop listItems manually?
Thank you in advance.
you might want to take a look here: https://stackabuse.com/how-to-loop-in-react-jsx/ . I hope this is what you are looking for
The map() method is the most commonly used function to iterate over an array of data in JSX. You can attach the map() method to the array and pass a callback function that gets called for each iteration. When rendering the User component, pass a unique value to the key prop.
JSX treat an array like a multiple elements. You can code like this:
function NumberList() {
return (
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
);
}
Or use an array. But when use an array, we need to add an unique key attribute for each element in array:
function NumberList() {
const listItems = [
<li key="1">1</li>,
<li key="2">2</li>,
<li key="3">3</li>,
];
return (
<ul>{listItems}</ul>
);
}
If you want to using one element, you can wrap all elements to a Fragment:
function NumberList() {
const listItems = (
<>
<li>1</li>
<li>2</li>
<li>3</li>
</>
);
return (
<ul>{listItems}</ul>
);
}
Use map is same as using array:
function NumberList() {
const numbers = [1, 2, 3];
const listItems = numbers.map((number) =>
<li key={number.toString()}>
{number}
</li>
);
return (
<ul>{listItems}</ul>
);
}
or using map directly in JSX:
function NumberList() {
const numbers = [1, 2, 3];
return (
<ul>
{
numbers.map((number) =>
<li key={number.toString()}>
{number}
</li>
)}
</ul>
);
}
About key attribute, please refer to React's document: (https://reactjs.org/docs/lists-and-keys.html#keys)[https://reactjs.org/docs/lists-and-keys.html#keys].

What should I use as a key for "row" elements in react?

I have a gallery that displays a number of books per row. This gallery takes an array of books as a prop and uses "itemsPerRow" prop to chunk the books into a 2 dimensional array and then loops through all the books to display the books in a grid-like structure.
export default function Gallery({ items, itemsPerRow, renderLink }) {
itemsPerRow = itemsPerRow ?? 3
const rows = chunk(items, itemsPerRow)
const renderEmptyItems = (itemsToRender) => {
const items = []
for(let n = itemsToRender; n > 0; n--) {
items.push(<GalleryItem key={`empty_${n}`} empty/>)
}
return items
}
return (
<div>
{
rows.map((row, index) => (
<div key={index} className="tile is-ancestor">
{row.map(item => <GalleryItem key={item.id} renderLink={renderLink} {...item}/>)}
{/* Add empty gallery items to make rows even */}
{index + 1 === rows.length && renderEmptyItems(itemsPerRow - row.length)}
</div>
))
}
</div>
)
}
However, unless I give each div representing a row a key, react complains about the lack of keys. As I understand it, using the index as a key doesn't really help react and should be avoided. So what should I use as a key here <div key={index} className="tile is-ancestor"> instead of the index?
Use a unique identifier (book.id, maybe book.title if it's unique) for the key props. If your data does not have a unique identifier, it's okay to use index.
You need to specify a value that uniquely identify the item, such as the id. You can read more about keys in the documentation.
Also it is not recommended to use indexes as keys if the order of your data can change, as React relies on the keys to know which components to re-render, the documentation I linked explains that further.
You can use the unique_identifier which differentiate each of the documents(probably, you should pass the document _id as a key prop in the row components)
<div className="row">
{notes.map((item) => {
return (
<div key={note._id} className="col-md-6">
<Component item={item} />
</div>
);
})}
</div>

Remove duplicates when calling from Github API in React

I have a function where I am calling the list of Filetypes from the gist API of a user by looping through it (https://api.github.com/users/getify/gists) :
const FileTags = ({files}) => {
return(
<div>
{
Object.keys(files).map(function (key) {
return(
<ul>
<li> {files[key].language } </li>
</ul>
)
})
}
</div>
);
}
I am able to successfully call the list of languages but the list is with a lot of duplicates, for example:
Markdown
Markdown
JavaScript
JavaScript
JavaScript
JavaScript
JavaScript
How do I filter out unique languages without them repeating such as
"Markdown Javascript"
?
Maybe something like this:
const FileTags = ( {files } ) =>
<div>
<ul>
{
[...new Set(Object.keys(files).map(key => files[key].language))]
.map( el => <li>{el}</li>)
}
</ul>
</div>
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
The Set object lets you store unique values of any type, whether
primitive values or object references.

How to loop over a number in React inside JSX

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>
)

How to map a nested array in React.js?

Issue: I can only render one iteration of my array.
My desired result of course is to get the entire length of array objects.
Adding [key] to my rendered object fields is the only method that gives me any output. Without declaring the key in this way, I get nothing
Child Component
...
const Potatoes = ({potatoes}) => {
const PotatoItems = potatoes.map((potato, key) => {
if ([potato] == ''){
return false
} else {
return (
<li key={key}>
<span>{potato[key].name}</span>
<span>{potato[key].flavor}</span>
</li>);
}
});
return (
<div>
<ul>
{PotatoItems}
</ul>
</div>
);
};
Parent Component
...
render () {
const potatoes = new Array(this.props.potatoes);
return (
<section style={divStyle}>
<Potatoes potatoes={potatoes} />
</section>
)
}
Simply removing new Array() from around the potatoes constant fixes your issue.
It seems like you may have created an unnecessary additional array.
Then you can remove those [key] references on your object in the child component and you should be good to go!
Does this fix your issue?

Categories