PAYATHON 2026

如何在 React 中返回 Object 的所有元素?

支付老李

结论

不要先对 payments[0] 调用 Object.keys()。partialRepayments 已经是数组,可以直接调用 map()。在每条还款记录中,再遍历 paymentsFields,通过 item.key 读取对应字段。

{partialRepayments.map((payment, paymentIndex) => (
  <div key={payment.orderId ?? paymentIndex}>
    {paymentsFields.map(item => (
      <div key={item.key}>
        <span>{item.title}</span>
        <span>{payment[item.key]}</span>
      </div>
    ))}
  </div>
))}

这样,每条部分还款记录都会生成一组字段,而不会只显示第一条。

原来的写法为什么无法正确展示

payments[0] 已经把数据范围限制在数组的第一项:

payments[0]

下面这段代码也没有真正遍历原数组:

[payments[0][val]].map(...)

方括号把 payments[0][val] 包装成了一个只有一个元素的新数组,因此 map() 只会执行一次。如果该值本身就是 partialRepayments 数组,那么回调中的 payment 仍然是整个数组,并不是单条还款记录。

还有一个问题是,箭头函数使用花括号后必须显式写出 return:

.map(val => {
  return (...);
})

原代码的外层回调没有返回 JSX,也可能造成内容无法渲染。

推荐写法

假设接口结果保存在 loan 中,可以先安全地取出数组:

const partialRepayments = loan?.partialRepayments ?? [];

然后直接渲染:

{partialRepayments.map((payment: any, paymentIndex: number) => (
  <section key={payment.orderId ?? paymentIndex}>
    {repaymentsFields.map(item => (
      <div key={item.key}>
        <span>{item.title}</span>
        <span>{payment[item.key] ?? '-'}</span>
      </div>
    ))}
  </section>
))}

如果贷款对象位于 payments 的第一项,数据路径可能是:

const partialRepayments = payments?.[0]?.partialRepayments ?? [];

完整示例如下:

const partialRepayments = payments?.[0]?.partialRepayments ?? [];

return (
  <div>
    {partialRepayments.length > 0 ? (
      partialRepayments.map((payment: any, paymentIndex: number) => (
        <div key={payment.orderId ?? paymentIndex}>
          {repaymentsFields.map(item => (
            <div key={item.key}>
              <strong>{item.title}</strong>
              <span>{payment[item.key] ?? '-'}</span>
            </div>
          ))}
        </div>
      ))
    ) : (
      <div>暂无部分还款记录</div>
    )}
  </div>
);

这里优先使用 orderId 作为 React 的 key。只有接口没有提供稳定的唯一标识时,才使用数组索引。

字段配置必须与 JSON 一致

示例配置中有以下字段:

{
  key: 'issuedDate',
  title: lang.CLIENTS.REPAYMENTS.ISSUED_DATE,
}

但给出的 JSON 并不包含 issuedDate,只有 started、completed、timestamp 等字段。因此,下面的表达式会得到 undefined:

payment['issuedDate']

如果页面要显示还款开始时间,可以把配置改成:

export const repaymentsFields = [
  {
    key: 'started',
    title: lang.CLIENTS.REPAYMENTS.ISSUED_DATE,
  },
  {
    key: 'period',
    title: lang.CLIENTS.REPAYMENTS.PERIOD_IN_DAYS,
  },
];

也可以根据实际业务含义选择 completed 或 timestamp,但要先确认页面中的“日期”具体对应哪个字段。

显示嵌套对象中的金额

repaidPrincipalAmount 是一个对象,不能直接当作字符串或数字显示:

{
  "amount": 250000.0
}

直接渲染下面的表达式会报错,因为 React 不能将普通对象作为子节点:

{payment.repaidPrincipalAmount}

可以让字段配置支持取值函数:

export const repaymentsFields = [
  {
    key: 'started',
    title: lang.CLIENTS.REPAYMENTS.ISSUED_DATE,
  },
  {
    key: 'period',
    title: lang.CLIENTS.REPAYMENTS.PERIOD_IN_DAYS,
  },
  {
    key: 'repaidPrincipalAmount',
    title: lang.CLIENTS.REPAYMENTS.PRINCIPAL_AMOUNT,
    getValue: (payment: any) => payment.repaidPrincipalAmount?.amount,
  },
];

渲染时优先调用 getValue:

{partialRepayments.map((payment: any, paymentIndex: number) => (
  <div key={payment.orderId ?? paymentIndex}>
    {repaymentsFields.map(item => {
      const value = item.getValue
        ? item.getValue(payment)
        : payment[item.key];

      return (
        <div key={item.key}>
          <span>{item.title}</span>
          <span>{value ?? '-'}</span>
        </div>
      );
    })}
  </div>
))}

与在组件中逐个判断字段相比,这种方式更容易维护,也能用于日期格式化:

{
  key: 'started',
  title: lang.CLIENTS.REPAYMENTS.ISSUED_DATE,
  getValue: (payment: any) =>
    payment.started
      ? new Date(payment.started).toLocaleString()
      : '-',
}

使用 TypeScript 定义数据类型

如果项目使用 TypeScript,尽量不要长期使用 any:

interface Amount {
  amount: number;
}

interface PartialRepayment {
  orderId: string;
  repaidPrincipalAmount: Amount;
  repaidInterestAmount: Amount;
  repaidOverdueAmount: Amount;
  repaidProlongationAmount: Amount;
  started: string;
  completed: string;
  period: number;
  timestamp: string;
}

组件中的遍历可以写成:

{partialRepayments.map((payment: PartialRepayment) => (
  <div key={payment.orderId}>
    <div>{payment.started}</div>
    <div>{payment.period}</div>
    <div>{payment.repaidPrincipalAmount.amount}</div>
  </div>
))}

处理这类数据时,应先找到 partialRepayments 数组并直接调用 map(),再为每条记录遍历字段配置。不要用 payments[0] 代替整组还款记录,也不要用 [value] 把数据包装成单元素数组。

备注:内容仅供参考。