React - 如何映射嵌套对象值?

时间:2017-04-15 08:00:14

标签: javascript reactjs object state

我只是想在状态对象中映射嵌套值。数据结构如下所示:

enter image description here

我想映射每个里程碑名称,然后映射该里程碑内的所有任务。现在我正在尝试使用嵌套的地图函数,但我不确定我是否可以这样做。

渲染方法如下所示:

render() {
    return(
      <div>
        {Object.keys(this.state.dataGoal).map( key => {
            return <div key={key}>>

                     <header className="header">
                       <h1>{this.state.dataGoal[key].name}</h1>
                     </header>
                     <Wave />

                     <main className="content">
                       <p>{this.state.dataGoal[key].description}</p>

                         {Object.keys(this.state.dataGoal[key].milestones).map( (milestone, innerIndex) => {
                             return <div key={milestone}>
                                      {milestone}
                                      <p>Index: {innerIndex}</p>
                                    </div>
                         })}
                     </main>

                   </div>
        })}
      </div>
    );
  }

我认为我可以通过将内部索引传递给这行代码来以某种方式实现该结果:{Object.keys(this.state.dataGoal[key].milestones)所以它看起来像:{Object.keys(this.state.dataGoal[key].milestones[innerIndex])

但我不确定如何通过innerIndex。我也尝试通过{milestone.name}获取里程碑名称,但这也不起作用。我猜那是因为我必须指定密钥。

有人有想法吗?或者我应该以完全不同的方式映射整个对象?

很高兴得到任何帮助, 的Jakub

3 个答案:

答案 0 :(得分:5)

您可以使用嵌套地图映射里程碑,然后映射任务数组:

render() {
  return (
    <div>
      {Object.keys(this.state.dataGoal.milestones).map((milestone) => {
        return {this.state.dataGoal.milestones[milestone].tasks.map((task, idx) => {
          return (
          //whatever you wish to do with the task item
          )
        })
      })}
    </div>
  )
}

答案 1 :(得分:1)

你想要的是flatMapflatMap接受一个数组和一个函数,该函数将应用于数组中的每个元素,您可以使用它来(例如)访问数组中每个对象内的属性。然后它返回一个新数组,其中包含lambda的返回值:

function flatMap(arr, lambda) {
  return Array.prototype.concat.apply([], arr.map(lambda))
}

在我们的例子中,我们没有数组,我们有一个对象,所以我们不能直接使用flatMap。我们可以使用Object.values将对象转换为其属性值的数组,然后创建一个使用传递的密钥访问对象的函数:

function tasksFromDataGoal(key) {
  return flatMap(Object.values(dataGoal[key].milestones), milestone => milestone.tasks)
}

工作示例:

function flatMap(arr, lambda) {
  return Array.prototype.concat.apply([], arr.map(lambda))
}

function tasksFromDataGoal(key) {
  return flatMap(Object.values(dataGoal[key].milestones), milestone => milestone.tasks)
}

const dataGoal = { 123: { milestones: { milestone1: { tasks: ['a', 'b'] }, milestone2: { tasks: ['c', 'd'] } } } }

alert(tasksFromDataGoal('123'))

flatMap的实施的作者:https://gist.github.com/samgiles/762ee337dff48623e729

答案 2 :(得分:0)

管理重构渲染方法:

&#13;
&#13;
  render() {
    return(
      <div>
        {Object.keys(this.state.dataGoal).map( (key, index) => {
          const newDataGoal = this.state.dataGoal[key].milestones;

          return <div key={key}>

                   <header className="header">
                     <h1>{this.state.dataGoal[key].name}</h1>
                   </header>
                   <Wave />

                   <main className="content">
                     <p>{this.state.dataGoal[key].description}</p><br /><br />

                       {Object.keys(this.state.dataGoal[key].milestones).map( (milestoneKey) => {
                         const milestonesData = this.state.dataGoal[key].milestones[milestoneKey];

                         return <div className="milestone-wrap" key={milestoneKey}>
                                  <label className="milestone-label">{milestonesData.name}</label>

                                    {Object.keys(milestonesData.tasks).map( (taskKey) => {
                                      return <div className="task clearfix" key={taskKey}>
                                                  <input
                                                    className="checkbox-rounded"
                                                    name="task"
                                                    type="checkbox"
                                                    checked={milestonesData.tasks[taskKey].done}
                                                    onChange={(e) => this.handleInputChange(e, key, taskKey)} />
                                                  <div className="task-content">
                                                    <p className="task-name">{milestonesData.tasks[taskKey].name}</p>
                                                    <p className="task-date">{milestonesData.tasks[taskKey].finishDate}</p>
                                                  </div>
                                             </div>

                                    })}

                                </div>

                       })}
                   </main>

                 </div>
          })}
      </div>
    );
  }
&#13;
&#13;
&#13;