在 React 中呈现 array. map()

我有一个问题,我试图使用数据数组渲染一个 <ul>元素。在下面的代码中,console.log运行良好,但是没有出现列表项。

var Main = React.createClass({
getInitialState: function(){
return {
data: dataRecent
}
},


render: function(){
return (
<div>
<ul>
{
this.state.data.map(function(item, i){
console.log('test');
<li>Test</li>
})
}
</ul>
</div>
)
}
});


ReactDOM.render(<Main />, document.getElementById('app'));

我做错了什么? 请随意指出任何不符合最佳实践的地方。

604716 次浏览

You are not returning. Change to

this.state.data.map(function(item, i){
console.log('test');
return <li>Test</li>;
})

You are implicitly returning undefined. You need to return the element.

this.state.data.map(function(item, i){
console.log('test');
return <li>Test</li>
})

Gosha Arinich is right, you should return your <li> element. But, nevertheless, you should get nasty red warning in the browser console in this case

Each child in an array or iterator should have a unique "key" prop.

so, you need to add "key" to your list:

this.state.data.map(function(item, i){
console.log('test');
return <li key={i}>Test</li>
})

or drop the console.log() and do a beautiful oneliner, using es6 arrow functions:

this.state.data.map((item,i) => <li key={i}>Test</li>)

IMPORTANT UPDATE:

The answer above is solving the current problem, but as Sergey mentioned in the comments: using the key depending on the map index is BAD if you want to do some filtering and sorting. In that case use the item.id if id already there, or just generate unique ids for it.

import React, { Component } from 'react';


class Result extends Component {




render() {


if(this.props.resultsfood.status=='found'){


var foodlist = this.props.resultsfood.items.map(name=>{


return (




<div className="row" key={name.id} >


<div className="list-group">


<a href="#" className="list-group-item list-group-item-action disabled">


<span className="badge badge-info"><h6> {name.item}</h6></span>
<span className="badge badge-danger"><h6> Rs.{name.price}/=</h6></span>


</a>
<a href="#" className="list-group-item list-group-item-action disabled">
<div className="alert alert-dismissible alert-secondary">


<strong>{name.description}</strong>
</div>
</a>
<div className="form-group">


<label className="col-form-label col-form-label-sm" htmlFor="inputSmall">Quantitiy</label>
<input className="form-control form-control-sm" placeholder="unit/kg"  type="text" ref="qty"/>
<div> <button type="button" className="btn btn-success"
onClick={()=>{this.props.savelist(name.item,name.price);
this.props.pricelist(name.price);
this.props.quntylist(this.refs.qty.value);
}
}>ADD Cart</button>
</div>






<br/>


</div>


</div>


</div>


)
})






}






return (
<ul>
{foodlist}
</ul>
)
}
}


export default Result;
let durationBody = duration.map((item, i) => {
return (
<option key={i} value={item}>
{item}
</option>
);
});

I've come cross an issue with the implementation of this solution.

If you have a custom component you want to iterate through and you want to share the state it will not be available as the .map() scope does not recognize the general state() scope. I've come to this solution:

`

class RootComponent extends Component() {
constructor(props) {
....
this.customFunction.bind(this);
this.state = {thisWorks: false}
this.that = this;
}
componentDidMount() {
....
}
render() {
let array = this.thatstate.map(() => {
<CustomComponent that={this.that} customFunction={this.customFunction}/>
});


}
customFunction() {
this.that.setState({thisWorks: true})
}
}






class CustomComponent extend Component {


render() {
return <Button onClick={() => {this.props.customFunction()}}
}
}

In constructor bind without this.that Every use of any function/method inside the root component should be used with this.that

Add up to Dmitry's answer, if you don't want to handle unique key IDs manually, you can use React.Children.toArray as proposed in the React documentation

React.Children.toArray

Returns the children opaque data structure as a flat array with keys assigned to each child. Useful if you want to manipulate collections of children in your render methods, especially if you want to reorder or slice this.props.children before passing it down.

Note:

React.Children.toArray() changes keys to preserve the semantics of nested arrays when flattening lists of children. That is, toArray prefixes each key in the returned array so that each element’s key is scoped to the input array containing it.

 <div>
<ul>
{
React.Children.toArray(
this.state.data.map((item, i) => <li>Test</li>)
)
}
</ul>
</div>

Dmitry Brin's answer worked for me, with one caveat. In my case, I needed to run a function between the list tags, which requires nested JSX braces. Example JSX below, which worked for me:

{this.props.data().map(function (object, i) { return <li>{JSON.stringify(object)}</li> })}

If you don't use nested JSX braces, for example:

{this.props.data().map(function (object, i) { return <li>JSON.stringify(object)</li>})}

then you get a list of "JSON.stringify(object)" in your HTML output, which probably isn't what you want.

Using Stateless Functional Component We will not be using this.state. Like this

 {data1.map((item,key)=>
{ return
<tr key={key}>
<td>{item.heading}</td>
<td>{item.date}</td>
<td>{item.status}</td>
</tr>
                

})}

Best Answer:

import React, { useState } from 'react';
import './App.css';


function App() {
// Array of objects containing our fruit data
let fruits = [
{ label: "Apple", value: "🍎" },
{ label: "Banana", value: "🍌" },
{ label: "Orange", value: "🍊" }
]


// Using state to keep track of what the selected fruit is
let [fruit, setFruit] = useState("⬇️ Select a fruit ⬇️")


// Using this function to update the state of fruit
// whenever a new option is selected from the dropdown
let handleFruitChange = (e) => {
setFruit(e.target.value)
}


return (
<div className="App">
{/* Displaying the value of fruit */}
{fruit}
<br />


<select onChange={handleFruitChange}>
{
fruits.map((fruit) => <option value={fruit.value}>{fruit.label}</option>)
}
</select>
</div>
);
}


export default App;