Looping <li> elements in JSX React - javascript

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].

Related

Performance benefits to dangerouslySetInnerHTML

I have a list of items and a user that wants to search those items. When the user’s search value matches the name of an item, I want to render that item with the matching part of the item's name in bold. For example:
const items = [‘milk’, ‘whole milk’, ‘2% milk’]
const searchValue = ‘milk’;
/* outputted HTML */
<ul>
<li>
<Strong>milk<Strong>
</li>
<li>
whole <Strong>milk<Strong>
</li>
<li>
2% <Strong>milk<Strong>
</li>
</ul>
The application is written in React and I wrote the following:
render() {
const { items, searchValue } = this.props;
return (
<ul>
{items.map((item) => {
const parts = item.split(new RegExp('(' + searchValue + ')'));
if (parts.length === 1) return null;
else return <li key={item}>{parts.filter((part) => (part === searchValue ? <strong>{part}</strong> : part))}</li>;
})}
</ul>
);
}
The code above preforms poorly sometimes taking seconds to render. This is unsurprising since a simple searchValue such as "a" can result in hundreds of items being rendered. I did notice however that if I use dangerouslySetInnerHTML, these performance problems disappear:
render() {
const { items, searchValue } = this.props;
return (
<ul>
{items.map((item) => {
if (!item.includes(searchValue)) return null;
const boldedItem = item.replace(new RegExp(searchValue), (match) => '<Strong>' + match + '</Strong>');
return <li key={item} dangerouslySetInnerHTML={{ __html: boldedItem }}></li>;
})}
</ul>
);
}
Does anyone know why dangerouslySetInnerHTML is preforming better here?
While I'll likely solve this problem by limiting the rendered search results (ex: https://github.com/bvaughn/react-window) instead of using dangerouslySetInnerHTML, I still want to know what is happening under the hood here.

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

how to use .map() in nodelist in javascript?

Why am i getting this error? How can i access and print the nodes when i'm selecting the <li> tags with querySelectorAll?
script.js:14 Uncaught TypeError: list.map is not a function
HTML
<ul class="wrapper1" id="testDiv">
<li class="cake">Carrots</li>
<li class="cake">Cake</li>
<li class="cake">Wheat</li>
<li class="cake">Balloons</li>
</ul>
JS
let list = document.querySelectorAll("li");
let items = list.map(elem => {
console.log(elem);
})
querySelectorAll() returns a static (not live) NodeList representing a list of the document's elements that match the specified group of selectors. Use array#from to convert NodeList to array then iterate through array#map.
let list = document.querySelectorAll("li");
let items = Array.from(list).map(elem => {
console.log(elem);
})
<ul class="wrapper1" id="testDiv">
<li class="cake">Carrots</li>
<li class="cake">Cake</li>
<li class="cake">Wheat</li>
<li class="cake">Balloons</li>
</ul>
In addition to Itang and Foo's suggestion, you can also use:
[].concat(document.querySelectorAll("li")).map((el) => { console.log(el); })
In fairness I think Foo's suggestion using spread syntax Is probably the most elegant, I'm just not sure how widely the spread operator is supported for NodeLists. (pasted below for reference)
[...document.querySelectorAll('li')].map((el) => { console.log(el); })
If you're using ES6, you can use [...selectors] syntax, like this:
let getMappingList = function (list) {
console.log(typeof list);
for (let item of list) {
console.log(item);
}
console.log("___________________");
list.map(item => console.log(item));
};
getMappingList([...document.querySelectorAll("li")]);
<ul class="wrapper1" id="testDiv">
<li class="cake">Carrots</li>
<li class="cake">Cake</li>
<li class="cake">Wheat</li>
<li class="cake">Balloons</li>
</ul>
After getting the list, we can also use map function, or looping the list using for...of... syntax.
Array(...selectors) is the same way to use:
let getMappingList = function (list) {
console.log(typeof list);
for (let item of list) {
console.log(item);
}
console.log("___________________");
list.map(item => console.log(item));
};
getMappingList(Array(...document.querySelectorAll("li")));
<ul class="wrapper1" id="testDiv">
<li class="cake">Carrots</li>
<li class="cake">Cake</li>
<li class="cake">Wheat</li>
<li class="cake">Balloons</li>
</ul>
I know this is an old thread but listed as #1 on Google search result. So here is an alternative to those in need.
let items = [].map.call(list, item => console.log(item));
I encountered the question of how to use a nodelist (result of document.querySelectorAll) with .map on my project and solved it by using a SPREAD operator to create an array from the nodelist.
Learning as I go so don't hesitate to correct me. It's weird that modern browsers can directly execute a foreach function to a nodelist but not map.
let list = document.querySelectorAll("li");
let items = [...list].map(elem => {
console.log(elem);
})
<ul class="wrapper1" id="testDiv">
<li class="cake">Carrots</li>
<li class="cake">Cake</li>
<li class="cake">Wheat</li>
<li class="cake">Balloons</li>
</ul>
edit : understood how snippets work / SPREAD not REST

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