I'm trying to only map a function to listItems if the condition is true, otherwise skip it. I have been trying different stuff but I don't want to return before the list is complete.
I have this code:
const listItems = (
<ul>
{desclist.map((point, index) =>
if (point.length < 2) {
<li key={index}>
<p>{point}</p>
</li>
)}
}
</ul>
);
return listItems;
}
If you return something within the .map function, it won't end the loop of the function and will still continue iterating. Instead, what you return will be put within the resulting array that .map returns. Meaning that if inside the .map you return a component depending on an if statement, and otherwise none, the result will be an array with all the components that were returned.
const listItems = (
<ul>
{
desclist.map((point, index) =>
if (point.length < 2) {
return <li key={index}>
<p>{point}</p>
</li>;
}
);
}
</ul>
);
If else will work under parentheses and also don’t use index directly as key instead append some text along with index to key prop so
Change
{desclist.map((point, index) =>
if (point.length < 2) {
<li key={index}>
<p>{point}</p>
</li>
)}
}
To
{desclist.map((point, index) => {
if (point.length < 2) {
return (<li key={'Key-'+index}>
<p>{point}</p>
</li>
)}
}
)}
Related
I have a simple React component that iterates over a list of items, and each item includes it as a Component. The trick is every 3rd list item, I want to inject a "special" extra li.
So, my "pseudo react code" looks something like this:
return (<ul>
{
data.myItems.items.map((item, index) => {
return (
<li><MyItem key={index} {...item} /></li>
{ (index % 3 === 0) &&
<li>Special LI</li>
}
);
})
}
</ul>);
This obviously doesn't work since my return(..) potentially returns 2 top-level elements (2 li's).
I can't wrap the 2 divs in something else it will break the semantics of ul/li (i need them all to be siblings in a list of depth 1).
I figure there has to be a simple way to do this that I'm overlooking.
Just wrap it in an empty tag. In react, it is called Fragment.
return (<ul>
{
data.myItems.items.map((item, index) => {
return (
<>
<li><MyItem key={index} {...item} /></li>
{ (index % 3 === 0) &&
<li>Special LI</li>
}
</>
);
})
}
</ul>);
You can use a fragment element. More on fragments here.
return (<ul>
{
data.myItems.items.map((item, index) => {
return (
<>
<li><MyItem key={index} {...item} /></li>
{ (index % 3 === 0) &&
<li>Special LI</li>
}
</>
);
})
}
</ul>);
When I just list the items directly, using index works. As in the following.
<ol className="item-list">
{
props.items.map((item, index) => (
<li key={index}>{item}</li>
))
}
</ol>
But when I create a custom component to represent the list item, using index doesn't seem to qualify as being unique... And I end up getting a warning, as in the following.
<ol className="item-list">
{
props.items.map((item, index) => (
<ShoppingItem
index={index}
item={item}
/>
))
}
</ol>
The ShoppingItem is a simple component, like the following.
const ShoppingItem = props => (
<li key={props.index}>{props.item}</li>
);
And the warning I get in the console is the following.
Warning: Each child in a list should have a unique "key" prop.
You should read carefully the react docs for Lists and Keys: Extracting components with keys. The key goes on the component being mapped, not what it renders.
Incorrect
const ShoppingItem = props => (
<li key={props.index}>{props.item}</li>
);
<ol className="item-list">
{
props.items.map((item, index) => (
<ShoppingItem
index={index}
item={item}
/>
))
}
</ol>
Correct
<ol className="item-list">
{
props.items.map((item, index) => (
<ShoppingItem
key={index} // <-- key goes here
item={item}
/>
))
}
</ol>
So I created this pagination component.and I get the error Error: Pagination(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null. in some parts of my app that I used whiles others works fine. I dont know what is going and how to fix it. This is my code. I tried other solutions but its still not working
const Pagination = ({ dataPerPage, totaldata, paginate }) => {
const [currentPage, setCurrentPage] = useState(0)
const pageNumbers = []
const int = Math.ceil(totaldata / dataPerPage)
if (int === 1) return
for (let i = 1; i <= int; i++) {
pageNumbers.push(i)
}
return (
<nav>
<ul className="pagination">
{pageNumbers.map(number => (
<li key={number} className="page-item">
<a
onClick={() => {
setCurrentPage(number)
paginate(number)
}}
href="#"
className="page-link"
>
{number}
</a>
</li>
))}
</ul>
</nav>
)
}
export default Pagination
The error message states This usually means a return statement is missing. Or, to render nothing, return null. Your component is returning undefined.
if (int === 1) return // <-- returns undefined!
Preventing a component from rendering
In rare cases you might want a component to hide itself even though it
was rendered by another component. To do this return null instead of
its render output.
You should return valid JSX. If you want a component to render nothing then the component should return null.
const Pagination = ({ dataPerPage, totaldata, paginate }) => {
const [currentPage, setCurrentPage] = useState(0);
const pageNumbers = [];
const int = Math.ceil(totaldata / dataPerPage);
if (int === 1) return null; // <-- return null to render nothing
for (let i = 1; i <= int; i++) {
pageNumbers.push(i);
}
return (
<nav>
<ul className="pagination">
{pageNumbers.map(number => (
<li key={number} className="page-item">
<a
onClick={() => {
setCurrentPage(number)
paginate(number)
}}
href="#"
className="page-link"
>
{number}
</a>
</li>
))}
</ul>
</nav>
);
}
This is my render
render() {
let products = this.state.products
return (
<ul>
{products.map((product, index) => Product({ key: index, product: product }))}
</ul>
);
}
I am using a unique key, and still get the warning
Warning: Each child in an array or iterator should have a unique "key"
prop.
That's not how you return a Component or pass it the key prop (or any other props...)
<ul>
{products.map((product, index) => (
<Product key={index} product={product} />
))}
</ul>
https://reactjs.org/docs/components-and-props.html#composing-components
I found this for you.
How to create unique keys for React elements?
It seems like you need to have a return for the key.
Or, as it states, npm packages already exist to declare unique keys.
You are not passing child elements to the ul
render() {
let products = this.state.products
return (
<ul>
{products.map((product, index) =>
<li key={index}>
{product}
</li>}
</ul>
);
}
I'm seeing this:
function Product(props) {
return (
<p key={props.key}>{props.product}</p>
)
}
function Main(props) {
let products = [ "foo", "bar", "baz"];
return (
<ul>
{products.map((product, index) => Product({key: index, product: product }))}
</ul>
);
}
ReactDOM.render(
<Main></Main>,
document.getElementById('example')
);
and this:
function Product(props) {
return (
<p>{props.product}</p>
)
}
function Main(props) {
let products = [ "foo", "bar", "baz"];
return (
<ul>
{products.map((product, index) => (
<li key={index}>
{Product({product: product })}
</li>
))}
</ul>
);
}
ReactDOM.render(
<Main></Main>,
document.getElementById('example')
);
Do what you're trying to accomplish.
If I had to guess (I don't have high confidence in this explanation), I would suspect that React requires a key prop on child components to so that it can quickly determine which elements need to be re-rendered when state changes. Therefore, passing a key prop won't actually achieve anything unless it's actually rendered as UI. The two examples above are rendering keys to the virtual DOM in the <p> and <li> respectively.
I have the following component
const list = (props) => {
const handler = function(){
};
var listItems = props.items.map(function(item, index){
return (
<li key={index} onClick={ handler }>
{item.text}
</li>
)
});
return (
<div>
<ul>
{listItems}
</ul>
</div>
)
}
On Click i'd like to get the index of the li clicked. Using ES6 and without binding how can i do this ?
Use an arrow function.
onClick={() => handler(index)}
You can actually get index without using an arrow function. The only thing you need to do is pass the index as an attribute and get that value from the event as e.target.getAttribute("your_attribute_name")
const list = (props) => {
const handler = function(e){
console.log(e.target.getAttribute("data-index")); //will log the index of the clicked item
};
var listItems = props.items.map(function(item, index){
return (
<li key={index} data-index={index} onClick={ handler }>
{item.text}
</li>
)
});
return (
<div>
<ul>
{listItems}
</ul>
</div>
);
}
you can set the index in the child as data-index and then you get this value in the handler function using event.currentTarget.dataset.index
This will prevent the re-rendering that causes when you use arrow function within render.
const handler = (event) => {
console.log(event.currentTarget.dataset.index);
};
const listItems = props.items.map((item, index) => {
return (
<li key={index} data-index={index} onClick={handler}>
{item.text}
</li>
)
});
This also works:
const list = props => {
const handler = index => () => {
}
const listItems = props.items.map((item, index) =>
<li key={index} onClick={handler(index)}>
{item.text}
</li>)
return <div>
<ul>{listItems}</ul>
</div>
}
You have another way of doing it, really easy to pass any variable to the handleClick function.
An that is using a curry function.
const ListComponent= ({listItems}) => {
const handleClick = (index) => (event) => {
[...]
}
return (
<ul>
{listItems.map((item, index) => (
<li
key={index}
onClick={ handler(index) }
>
{item.text}
</li>
))}
</ul>
)
}