Not looping through data with ES6 Map function - javascript

I have array that i want to map through the values and i can not get the ES6 map to work correctly. Below is my code.
Thanks for the help.
0: "FOLDER2"
1: "FOLDER3
renderNames = () => {
const listItems = this.props.clickedFolderNames
.map((number, index) => <ListItem key={index} value={number} />);
return (
<ul>
{listItems}
</ul>
);
}

You need to wrap your anonymous function block in curly brackets and return a value if you are splitting it over multiple lines:
.map((number,index) => {
return (<ListItem key={index}
value={number} />)
});
return (
<ul>
{listItems}
</ul>
);
}

Related

TypeError: Cannot read property 'map' of null

I couldn't understand why...here is the GitHub repository: https://github.com/Dronrom/React-test
That’s because you initialized peopleList as null in your component. So map works only on arrays so you need to check peopleList whether its really an array before doing map on it so
Change
renderItems(arr) {
return arr.map(({id, name}) => {
return (
<li className="list-group-item"
key={id}
onClick={() => this.props.onItemSelected(id)}>
{name}
</li>
);
});
}
To
renderItems(arr) {
if(arr){
return arr.map(({id, name}) => {
return (
<li className="list-group-item"
key={id}
onClick={() => this.props.onItemSelected(id)}>
{name}
</li>
);
});
}
}
I think your issue may be that react renders once before componentDidMount(). This is an issue because your calling map on arr which is null. const { peopleList } = this.state; you set people list to your current state which you set as default to be null, state = {peopleList: null}; then you later call this.renderItems(peopleList); which people list is still null at this moment so you are getting the Cannot read property 'map' of null error.
I belive something like componentWillMount is what you need instead. I recommend looking at this post which has a similar issue of react life cycle methods. React render() is being called before componentDidMount()
the answer is very simple: the type of the input isn't array type, it might be null or undefined. so that it doesn't have .map function.
How to fix:
Make sure your input must be array type before call renderItems().
render(){
const { peopleList } = this.state;
const items = (peopleList && peopleList.length) ? this.renderItems(peopleList) : null;
return(
<ul className="item-list list-group">
{items}
</ul>
);
}
Or:
Make sure your input must be array type before do mapping:
renderItems(arr) {
return !arr ? null : arr.map(({id, name}) => {
return (
<li className="list-group-item"
key={id}
onClick={() => this.props.onItemSelected(id)}>
{name}
</li>
);
});
{product.size?.map(c=>(
<FilterSizeOption key={c}>{c}</FilterSizeOption>
))}
Wrapping the return statement with a if statement worked for me
So changed
return (
<div>
<Navbar />
{countries.map((country, i) => {
return (
<div>
<span key={`${country.name.common}${i}`}>
{country.name.common}
</span>
</div>
);
})}
</div>
);
to this
if (countries) {
return (
<div>
<Navbar />
{countries.map((country, i) => {
return (
<div>
<span key={`${country.name.common}${i}`}>
{country.name.common}
</span>
</div>
);
})}
</div>
);
}

<UL> list item not being added in React

So this is my props if I console.log(this.props)
list:Array(1):
{user: "Jack Nicholson", userid: "5b684ed8d3eb1972b6e04d32", socket: "1c0-Jb-kxe6kzPbPAAAD"}
However when I map through my list and use component <UserItem user={user.user} />; My UserItem keeps returning undefined.
render() {
const UserItem = user => (
<li>
<div className="btn-group dropup">
<button
type="button"
className="btn btn-secondary dropdown-toggle"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
>
{user}
{console.log(user)}
</button>
<div className="dropdown-menu" />
</div>
</li>
);
return (
<ul>
{this.props.list.map((user, i) => {
console.log(this.props);
<UserItem user={user.user} />;
})}
</ul>
);
}
Arrow function in JS come in two forms: "concise body" and "block body". In concise form, as in your const UserItem = user => ( function, the provided expression is implicitly returned.
However, in block form, as in your this.props.list.map((user, i) => { function, you must use an explicit return statement.
Try adding one to your code:
{this.props.list.map((user, i) => {
console.log(this.props);
return <UserItem user={user.user} />;
})}
You could simply use round brackets instead of curly braces;
return (
<ul>
{
this.props.list.map((user, i) => (
<UserItem user={user.user} />
))
}
</ul>
);
If you are getting the list as API response then handle the initial rendering also.However,return your UserItem component in the map function.try this code
return (
<ul>
{this.props.list && this.props.list.map((user, i) => {
console.log(this.props);
return <UserItem user={user.user} />;
})}
</ul>
);
You need to add a return statement before <UserItem user={user.user} /> ,also make sure to check if this.props.list exists before rendering it.
like so:
{this.props.list? this.props.list.map((user, i) => {
console.log(this.props);
return <UserItem user={user.user} />;
}):<span/>}

Map return multi components

i'm trying to maping two component but i get this error :
Module build failed: SyntaxError: Unexpected token (72:7)
import AlertListItem from '~/components/Dashboard/AlertListItem'
import AlertItem from '~/components/Dashboard/AlertItem'
let items
if (result) {
items = result.map((item, index) =>
return(
<div>
<AlertListItem key={item.id} item={item} onPopup={this._onSelect} index={index} />
<AlertItem id={item.id} item={item} onClose={this._onDeselect} />
</div>
)
)
any solution ?
When using a concise arrow function (no {}), you don't use the return keyword; the body of the concise arrow function is a single expression, but return is a statement. (You also have a ) instead of } closing the if block.)
So:
import AlertListItem from '~/components/Dashboard/AlertListItem'
import AlertItem from '~/components/Dashboard/AlertItem'
let items
if (result) {
items = result.map((item, index) =>
<div>
<AlertListItem key={item.id} item={item} onPopup={this._onSelect} index={index} />
<AlertItem id={item.id} item={item} onClose={this._onDeselect} />
</div>
)
}
Example (this also has the change called out in the "Side Note" below):
// Setup:
const AlertListItem = props =>
<div>{props.children}</div>;
const AlertItem = props =>
<div>Item #{props.id}</div>;
const result = [
{id: 1}, {id: 2}, {id: 3}
];
// Your corrected code (with the event handlers removed,
// don't need them for the example)
let items;
if (result) {
items = result.map((item, index) =>
<div key={item.id}>
<AlertListItem item={item} index={index} />
<AlertItem id={item.id} item={item} />
</div>
)
}
// Show it
ReactDOM.render(
<div>{items}</div>,
document.getElementById("react")
);
<div id="react"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
Just for completeness, here's a simpler example of a concise arrow function:
array.sort((a, b) => a - b);
Note how the body is just the expression a - b.
And the equivalent verbose one:
array.sort((a, b) => { return a - b; });
Since we've used {...}, it's a full function body block, which contains statements, so we use return to return a value.
Side note: You need to put the key on the div, not the AlertListItem; if you use the non-minified library, it'll warn you about getting key wrong. I've moved key in my example above.
You are missing a curly braces for map:
items = result.map((item, index) => {...}

react and conditional rendering

Currently I am using the following code to conditionally render some HTML based on hasLocations variable.
Code works, but I wish to know if there is a better way to achieve the same result, for example, I am not sure having two return is a good practice.
const Finder = ({ locations, onLocationClick }) => {
let hasLocations = locations.length > 0
if (hasLocations) {
return (
<ul>
{locations.map((location, index) =>
<Location
key={index}
{...locations[index]}
onLocationClick={() => onLocationClick(location)}
/>
)}
</ul>
)
} else {
return (null)
}
}
Alternatively you chould use conditional rendering. For your example, this would look like this.
const Finder = ({ locations, onLocationClick }) => {
return (
<ul>
{locations.length > 0 &&
locations.map((location, index) =>
<Location
key={index}
{...locations[index]}
onLocationClick={() => onLocationClick(location)}
/>
)}
</ul>
);
}
EDIT: My solution would be the following.
I would avoid adding any logic in it(AKA presentational component). So it would become
const Finder = ({ locations, onLocationClick }) => {
return (
<ul>
locations.map((location, index) =>
<Location
key={index}
{...locations[index]}
onLocationClick={() => onLocationClick(location)}
/>
)
</ul>
);
}
And when you need to use it you can do something like this:
return (
<div>
{locations.length > 0 && Finder}
</div>
);
There's nothing wrong with using multiple returns in a function, but when you do it's good practice to put a "default" return as the last statement in the function to make it more apparent that the function always returns something.
In your case that means you could move your return (null) (no need to wrap null in brackets, btw) statement out of the else clause and just put it as the last statement of the function.
It's also possible to use a single return statement with ternary in your return, like this:
return locations.length > 0 ? (
<ul>
{locations.map((location, index) =>
<Location
key={index}
{...locations[index]}
onLocationClick={() => onLocationClick(location)}
/>
)}
</ul>
) : null

i is not defined using map() with ES6

Trying to create a li in react but failed. Error is near the map(), I got error of i is not defined, why?
const TodoItems = React.creatClass({
getInitialState() {
return {
items : [
{id:1,name:"Gym"},
{id:2,name:"Jump"},
{id:3,name:"Racing"}
]
}
},
renderItem(){
return(
<ul>
this.state.items.map(item,i =>
<li key={i}>item.name</li>
)
</ul>
)
},
render(){
return (
<renderItem />
)
}
})
When you have multiple arguments for an arrow function, you need to put () around them. So:
this.state.items.map((item,i) =>
// ------------------^------^
<li key={i}>item.name</li>
)
Your original code calls map with item as its first argument, and an arrow function taking a single argument (i) as its second argument.
You also need to put item.name in {} and put the call to map in {}:
renderItem(){
return(
<ul>
{this.state.items.map((item,i) =>
<li key={i}>{item.name}</li>
)}
</ul>
)
Then it works:
const { Component } = React;
const { render } = ReactDOM;
const TodoItems = React.createClass({
getInitialState() {
return {
items : [
{id:1,name:"Gym"},
{id:2,name:"Jump"},
{id:3,name:"Racing"}
]
}
},
renderItem(){
return(
<ul>
{this.state.items.map((item,i) =>
<li key={i}>{item.name}</li>
)}
</ul>
)
},
render(){
return this.renderItem();
}
});
render(<TodoItems /> , document.getElementById('items'));
<div id="items"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
That became clear to me when I used Babel's REPL to compile the JSX and realized I was seeing "this.state.map((item,i) =>" as a string.
try this :
renderItem(){
return(
<ul>
{this.state.items.map((item,i) => {
return(
<li key={i}>item.name</li>);
})}
</ul>
)

Categories