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

IT技术 javascript reactjs object state
2021-03-31 02:50:31

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

在此处输入图片说明

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

渲染方法如下所示:

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个回答

您可以使用嵌套映射映射里程碑和任务数组:

 render() {
  return (
    <div>
      {Object.keys(this.state.dataGoal.milestones).map((milestone) => {
        return (
          <div>
            {this.state.dataGoal.milestones[milestone].tasks.map((task, idx) => {
              return (
              //whatever you wish to do with the task item
              )
            })}
          </div>
        )
     })}
    </div>
  )
}
@mcmwhfy 我认为您在这里面临的问题是因为返回嵌套数据而没有包装在 div 中,但是如果您使用最新版本的 react,您可以简单地返回一个数组,即映射结果。无论如何,我更新了我的答案以处理包装 div
2021-05-28 02:50:31
你说的有道理,但我不明白为什么我的例子在对象看起来像的地方不起作用: [ { id: 1, name: "Leanne Graham", username: "Bret", email: "Sincere@april.biz", address: { street: "Kulas Light", suite: "Apt. 556", city: "Gwenborough", zipcode: "92998-3874", geo: { lat: "-37.3159", lng: "81.1496" } } ]
2021-06-07 02:50:31
@Jakub Kašpar 这对你有用吗?因为除了错误的闭括号之外,这个例子对我不起作用:|
2021-06-14 02:50:31

你想要的是flatMap. flatMap接受一个数组和一个将应用于数组中每个元素的函数,您可以使用它来(例如)访问数组中每个对象内的属性。然后它返回一个新数组,其中包含来自其的返回值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)
}

工作示例:

这个实现的作者flatMaphttps : //gist.github.com/samgiles/762ee337dff48623e729

@FaustoNA 感谢您的回复。我从来没有听说过这样的功能,所以再次感谢。我只是想实施这个解决方案,但我做对了。我把dataGoaltasks常量放在第一个里面Object.keys(this.state.dataGoal).map以获得像这样的键值:const newDataGoal = this.state.dataGoal[key].milestones;and const tasks = this.flatMap(Object.values(newDataGoal.milestones), milestone => milestone.tasks)但我得到了Uncaught TypeError: Cannot convert undefined or null to object. 我做错了吗?再次感谢您的帮助。:)
2021-06-02 02:50:31
没关系,错误可能如下: 1. 您正在使用this.flatMap. 你应该把flatMap放在其他地方,不用this,flatMap是一个实用函数,与你的组件没有直接关系。2. 如果您的应用程序执行网络请求,您可能会传递undefinedObject.keys. 尝试if (this.state.dataGoal)然后应用您的逻辑。
2021-06-05 02:50:31

设法重构渲染方法:

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