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>
)
Related
Suppose I have a react function with props active.
// About Page
export default function About() {
return <Menu active="about" />;
}
// Menu Component
function Menu(props) {
const items = ["home", "about", "services", "contact"];
return (
<nav>
{items.map((item, index) => {
console.log(props);
return <li className={`${props.active === item && "active"}`}> {item} </li>;
})}
</nav>
);
}
How do I get the props.active inside the map() function? it's returning undefined right now.
Converted to snippet, Seems props is getting correctly.
(not related, but minor fix, if you use && in class name generation, for the falsy condition classname will be "false")
function About() {
return <Menu active="about" />;
}
function Menu(props) {
const items = ["home", "about", "services", "contact"];
return (
<nav>
{items.map((item, index) => {
console.log(props);
return (
<li className={`${props.active === item ? "active" : "inactive"}`}> {item} </li>
);
})}
</nav>
);
}
ReactDOM.render(<About />, document.getElementById('app'))
.active {
color: red
}
.inactive {
color: grey
}
<script crossorigin src="https://unpkg.com/react#17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#17/umd/react-dom.development.js"></script>
<div id="app"> </div>
The above sample code in question works flawlessly.
In my project, I was actually modifying the wrong page to provide props, thus got {}
So, I'm writing this answer so that other people won't spend time on it.
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>
);
}
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>
);
}
I have a list of item, and upon on click of the delete button the item will get removed. I know the steps to do it but I'm stuck on how can I pass the key to the dlt_item scope.
http://jsfiddle.net/3Ley7uac/1/
var App = React.createClass({
getInitialState(){
return {
items:[1,2,3]
}
},
dlt_item(key){
//how to get index/id here?
},
renderItem(){
return this.state.items.map((item,i)=> <li key={i}>{item}
<button>Edit</button>
<button onClick={this.dlt_item}>Delete</button>
</li>
)
},
render(){
return(
<ul>
{this.renderItem()}
</ul>
)
}
})
You need to bind this.dlt_item as
<button onClick={this.dlt_item.bind(this, i)}>Delete</button>
and in your dlt_item function you can splice your state array from this index passed.
Code
var App = React.createClass({
getInitialState(){
return {
items:[1,2,3]
}
},
dlt_item(key){
console.log(key);
this.state.items.splice(key, 1);
this.setState({items: this.state.items});
//how to get index/id here and do setState
},
renderItem(){
return this.state.items.map((item,i)=> <li key={i}>{item}
<button>Edit</button>
<button onClick={this.dlt_item.bind(this, i)}>Delete</button>
</li>
)
},
render(){
return(
<ul>
{this.renderItem()}
</ul>
)
}
})
React.render(<App />, document.getElementById('container'));
JSFIDDLE
Instead of splice you can use filter as
dlt_item(key){
var items = this.state.items.filter(function(obj){
return obj != (key + 1);
});
console.log(items);
this.setState({items: items});
//how to get index/id here and do setState
},
JSFIDDLE
Use .bind(this, yourKey)
In your example:
var App = React.createClass({
getInitialState(){
return {
items: [1, 2, 3]
}
},
dlt_item(key){
console.log(key);
},
renderItem(){
return this.state.items.map((item, i) => <li key={i}>{item}
<button>Edit</button>
<button onClick={this.dlt_item.bind(this, item)}>Delete</button>
</li>
)
},
render(){
return (
<ul>
{this.renderItem()}
</ul>
)
}
});
React.render(<App />, document.getElementById('container'));
Another way to achieve the same result could be to return a curried function from you Component
The method will take a value and wait for the event to be called before executing the action.
I prefer this way as I like to limit the javascript in JSX as much as possible.
dlt_item(key){
// return the event listener
return function(e) {
// do something with the state
}.bind(this) // bind the inner functions this to the Component
}
The when you want to call the function you can do it like this
<button onClick={this.dlt_item(i)}>Delete</button>
var App = React.createClass({
getInitialState(){
return {
items:[1,2,3]
}
},
// this function will take your key
dlt_item(key){
// return the event listener
return function(e) {
this.setState({
items: splice(this.state.items, key, 1)
})
}.bind(this)
},
renderItem(){
return this.state.items.map((item,i)=> (
<li key={i}>{item}
<button>Edit</button>
<button onClick={this.dlt_item(i)}>Delete</button>
</li>
))
},
render(){
return(
<ul>
{this.renderItem()}
</ul>
)
}
})
// immutable splice helper function
const splice = (arr, index, count = 0, ...items) => {
return [
...arr.slice(0, index),
...items,
...arr.slice(index + count)
]
}
ReactDOM.render(
<App />,
document.getElementById('app')
)
<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>
<main id="app"></main>
Anything wrong with my map method?
var App = React.createClass({
getInitialState(){
return {
items:[1,2,3]
}
},
renderItem(){
return(
this.state.items.map((item,i))=>
<li key={i}> {item} </li>
)
},
render(){
return(
<ul>
{this.renderItem()}
</ul>
)
}
})
Couldn't see anything rendered, checked the console, no error found.
You have a syntax problem:
this.state.items.map((item,i))=>
^
Remove that close parenthesis, and place it beside the next close parenthesis:
return(
this.state.items.map((item,i)=>
<li key={i}> {item} </li>
))
First of all you need to get rif of the extra ) in the map parameters list
this.state.items.map((item,i))=> to this.state.items.map((item,i)=>
Secondly you need to add another ) to close the return statement
var App = React.createClass({
getInitialState(){
return {
items:[1,2,3]
}
},
renderItem(){
return(
this.state.items.map((item,i)=>
<li key={i}> {item} </li>
)
)
},
render(){
return(
<ul>
{this.renderItem()}
</ul>
)
}
})
ReactDOM.render(<App/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react-dom.min.js"></script>
<div id="app"></div>
Try this, IMO it's cleaner this way
var App = React.createClass({
getInitialState(){
return {
items:[1,2,3]
}
},
renderItem(item, index){
return(
<li key={index}> {item} </li>
)
},
render(){
return(
<ul>
{this.state.items.map(this.renderItem, this)}
</ul>
)
}
})
renderItem(){
return(
this.state.items.map((item,i)=> {
return <li key={i}> {item} </li>;
}
)
},
problem is in .map, you have to place code in {} and return