如何在JSX React中循环遍历对象

3

我有一个嵌套对象的数据,我想从中获取我的需求数据,并循环遍历该对象并在UI上呈现出来,但我不知道如何做到这一点,因为UI完全动态依赖于data

我的数据:

const countData = {
  "current_month": {
    "total_employes": 6,
    "ariving": "+3",
    "exiting": "-1",
    "current_month": "April    2020",
    "__typename": "CurrentMonthTotalEmp"
  },
  "previous_month": {
    "total_employes": "3",
    "arrived": "+2",
    "exited": "-2",
    "previous_month": "March 2020",
    "__typename": "PrevMonthTotalEmp"
  },
  "__typename": "CurPrevMonthEmps"
}

我想将其转换为数组,我这样做:

const finalData = Object.entries(countData);

现在我想要循环它:

请查看我的 codesandbox 查看完整代码

这里在我的 codesandbox 里,我使用 HTML 静态渲染。


UI/数据动态如何?您尝试在哪里呈现这个“finalData”?您的期望结果是什么? - Drew Reese
@DrewReese 请检查我提供的 CodeSandbox 链接 https://codesandbox.io/s/ecstatic-antonelli-z2c59,我正在使用静态 HTML 制作我的 UI,现在想通过循环使其动态化。 - manish thakur
是的,我的问题源自于您的沙盒,因为我没有看到任何尝试映射任何内容,并且它并不明显动态地是什么。您只显示两个月的数据吗?还是会有更多?您想将那个“奇怪”的 __typename 属性映射吗? - Drew Reese
@DrewReese,__typename不会被映射,因为我正在使用react-apollo-client。动态是整个UI,正如您所看到的,我目前正在静态地放置“year arrived”信息。现在我想从JSON数据中获取它们,并且始终只有两个月的数据,只有计数和月份年份会有所变化。 - manish thakur
5个回答

3

大多数 React 应用程序将使用数据来呈现 UI。这是 React 擅长的。

步骤 1:创建可复用组件

您需要创建一个接收每个月份属性(total_employeesarivingexitingcurrent_month)并正确渲染它们的 React 组件。

例如:

const MonthComponent = ({ total_employees, ariving, exiting, current_month }) => {

  //above return you can alter your data however you want using normal javascript

  return (
    //in 'return' you can return HTML or JSX to render your component.
    <div>
      <p>{total_employees}</p>
      <p>{ariving}</p>
      <p>{exiting}</p>
      <p>{current_month}</p>
    </div>
  );
};

步骤二:循环遍历数据并呈现可重用组件

现在,在您的父组件中,您可以循环遍历数据数组。

const ParentComponent = () => {

  const countData = {
    "current_month": {
      "total_employes": 6,
      "ariving": "+3",
      "exiting": "-1",
      "current_month": "April    2020",
      "__typename": "CurrentMonthTotalEmp"
    },
    "previous_month": {
      "total_employes": "3",
      "arrived": "+2",
      "exited": "-2",
      "previous_month": "March 2020",
      "__typename": "PrevMonthTotalEmp"
    },
    "__typename": "CurPrevMonthEmps"
  }

  const months = Object.keys(countData); // ["current_month", "previous_month"]

  return (
    months.map(month => (
      // map over months and render your reusable component for each month
      <MonthComponent {...countData[month]} />
    ))
  );
};

注意:在...countData[month]中使用展开语法可以将countData[month]中的每个键值对都传递为一个属性。我也可以这样写:
<MonthComponent
  total_employees={countData[month].total_employees}
  arrived={countData[month].arrived}
  exited={countData[month].exited}
  previous_month={countData[month].previous_month}
/>

我认为在这里不需要创建两个组件,我尝试通过循环map来解决问题,但是出现了问题。 - manish thakur
你的沙盒示例展示了两个非常相似的UI“块”。建议为这些块创建单独的组件,以最小化需要重复编写相同代码的情况。 - Luïs
但是除此之外,如果您不想使用第二个组件,您仍然可以在map函数中映射Object.keys并动态地呈现所需内容。 - Luïs

1

有很多代码重复,我们想要减少这种情况(DRY原则)。首先,找到抽象描述您UI的通用代码,即具有月/年标签、一些到达/离开字段和标签以及员工计数的组件。将您想要显示的内容转换为一个接受这些“标准化”道具的组件。

const MonthData = ({
  arrive,
  arriveLabel,
  exit,
  exitLabel,
  totalEmployees,
  month,
}) => (
  <Fragment>
    <label className="monthYr" align="left">
      {month}
    </label>
    <div className="row countDiv">
      <div className="col-12 col-sm-12 col-md-6 col-lg-6 col-xl-6 total">
        <label className="totalHeading">Total employees</label>
        <div className="totalCount">{totalEmployees}</div>
      </div>

      <div className="col-12 col-sm-12 col-md-6 col-lg-6 col-xl-6">
        <button className="btn btn-outline-secondary button_Count form-control">
          {arriveLabel}
          <span className="badge badge-pill badge-primary ml-2">
            {arrive}
          </span>
        </button>
        <button className="btn btn-outline-secondary form-control">
          {exitLabel}
          <span className="badge badge-pill badge-primary ml-2">
            {exit}
          </span>
        </button>
      </div>
    </div>
  </Fragment>
);

我认为我不会像你这样对它们进行映射,因为先前和当前月份有不同的标签,并且您一次只显示两个月。只需从countData中解构出这两个月的数据即可。
const { current_month, previous_month } = countData;

return (
  <div className="row container-fluid">
    <div className="form-control graphHeading"> Manpower Graph</div>
    <div className="col-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
      <div className="row widthContainer">
        <div className="col-12 col-sm-12 col-md-6 col-lg-6 col-xl-6">
          <MonthData
            arrive={previous_month.arrived}
            arriveLabel="arrived"
            exit={previous_month.exited}
            exitLabel="exited"
            month={previous_month.previous_month}
            totalEmployees={previous_month.total_employees}
          />
        </div>
        <div className="col-12 col-sm-12 col-md-6 col-lg-6 col-xl-6">
          <MonthData
            arrive={current_month.arriving}
            arriveLabel="arriving"
            exit={current_month.exiting}
            exitLabel="exiting"
            month={current_month.current_month}
            totalEmployees={current_month.total_employees}
          />
        </div>
      </div>
    </div>
  </div>
);

嘿,你能帮我处理一下 CodeSandbox 的例子吗?这样我就可以查看实时示例了。 - manish thakur
@manishthakur 你是说把我的代码复制/粘贴到你的沙盒里吗?当然可以。 - Drew Reese
我不能在单个组件中完成这个任务,因为我有很多其他与此相关的事情。 - manish thakur
@manishthakur 抱歉,忘记连接 totalEmployees 属性。回答和沙盒已更新。 - Drew Reese
显示剩余2条评论

1
你可以使用:

{
    Object.keys(countData).map(key=>{
        const month = countData[key]
        return(
            //you have access to month
            <div>{month.total_employes}</div>
        );
    })
}

1
您可以在JSX代码中这样做:

{finalData.map(value => (
  <div>{value.something}</div>
))}

1

首先,您需要将countData转换为适合我们运行循环的正确结构。要做到这一点,您需要将其转换为以下数组:

const finalData = Object.values(countData)

这样做后,我们现在可以使用map函数遍历finalData变量,如下所示。

{finalData.map(data => (
  <div>{data.total_employes}</div>
  <div>{data.ariving}</div>
))}

此外,为了处理对象中缺失的键/值,您可以执行以下操作。
{finalData.map(data => (
  <div>{data.total_employes ? data.total_employes : 'NA'}</div>
  <div>{data.ariving ?  data.ariving : 'NA'}</div>
))}

希望这有所帮助。

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