在React中渲染一个数组.map()

106

我遇到了一个问题,尝试使用数据数组来渲染 <ul> 元素。在下面的代码中,控制台日志正常工作,但列表项未出现。

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

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

10个回答

149

Gosha Arinich 是正确的,你应该返回你的 <li> 元素。但是,在这种情况下,你应该在浏览器控制台中看到令人讨厌的红色警告。

数组或迭代器中的每个子元素都应该有一个唯一的“key”属性。

所以,你需要将 “key” 添加到你的列表中:

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

或者删除console.log()并使用es6箭头函数来编写简洁的单行代码:

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

重要更新:

上面的答案解决了当前问题,但是如Sergey在评论中提到的:如果您想进行一些过滤和排序,使用依赖于地图索引的键是不好的。在这种情况下,请使用item.id(如果已经存在id),或者仅为其生成唯一的标识符。


当我将这组<li>添加到<ul>中时,控制台仍会显示相同的红色警告。如何消除它? - informer
嘿!你还需要帮忙吗?是同样的“数组或迭代器中的每个子元素都应该有一个唯一的“key”属性”的问题吗? - Dmitry Birin
“key” 必须是唯一的。在对 “this.state.data” 进行排序后,您的代码将会出现错误,因为 “key” 总是依赖于数组中的索引。 - Sergey Podgornyy
1
@SergeyPodgornyy 完全同意,我很久以前就写过这个了。更新了答案。感谢跟进! - Dmitry Birin

18

你没有返回。请更改为

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

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

10
欢迎来到Stack Overflow!感谢您提供这段代码片段,它可能会提供一些有限的即时帮助。通过展示为什么这是一个好的解决方案,适当的解释将极大地提高其长期价值,并使其对未来具有类似问题的读者更有用。请编辑您的答案以添加一些解释,包括您所做出的假设。 - Suraj Rao

9

使用无状态函数组件,我们将不再使用 this.state。像这样:

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

4
你隐式地返回了undefined。你需要返回该元素。
this.state.data.map(function(item, i){
  console.log('test');
  return <li>Test</li>
})

3

最佳答案:

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;

2
除了Dmitry的回答之外,如果您不想手动处理唯一键ID,可以使用React文档中提出的React.Children.toArrayReact documentation

React.Children.toArray

将子元素的不透明数据结构作为一个扁平数组返回,并为每个子元素分配键。如果您想在渲染方法中操作子元素集合,特别是在将其向下传递之前重新排序或切片,这将非常有用。
注意:React.Children.toArray()会更改键以保留嵌套数组的语义,当展开子元素列表时。也就是说,toArray会为返回的数组中的每个元素的键加上前缀,使得每个元素的键都限定于包含它的输入数组。
 <div>
    <ul>
      {
        React.Children.toArray(
          this.state.data.map((item, i) => <li>Test</li>)
        )
      }
    </ul>
  </div>

0

我在实现这个解决方案时遇到了一个问题。

如果您有一个自定义组件要进行迭代,并且想要共享状态,那么通用的state()作用域将不可用于.map()作用域。我已经找到了以下解决方案:

`

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()}}
    }
}

在构造函数中绑定时不需要使用 this.that。 根组件内部的每个函数/方法的使用都应该带上 this.that

0
Dmitry Brin的答案对我有用,但有一个注意点。在我的情况下,我需要在列表标签之间运行一个函数,这需要嵌套的JSX大括号。以下是我使用的示例JSX:
{this.props.data().map(function (object, i) { return <li>{JSON.stringify(object)}</li> })}

如果您不使用嵌套的JSX括号,例如:

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

然后您会在HTML输出中获得一个"JSON.stringify(object)"列表,这可能不是您想要的。


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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接