如何通过使用map和join来渲染React组件


102

我有一个要显示字符串数组的组件。代码看起来像这样。

React.createClass({
  render() {
     <div>
        this.props.data.map(t => <span>t</span>)
     </div>
  }
})

运行正常。例如,如果props.data = ['tom','jason','chris'] ,则页面中的渲染结果为tomjasonchris

然后,我想使用逗号连接所有名称,因此我将代码更改为

this.props.data.map(t => <span>t</span>).join(', ')

但是,渲染的结果是[Object],[Object],[Object]。

我不知道如何解释对象成为要渲染的反应组件。有什么建议吗?

Answers:


147

一个简单的解决方案是不使用reduce()第二个参数且不传播先前的结果:

class List extends React.Component {
  render() {
     <div>
        {this.props.data
          .map(t => <span>{t}</span>)
          .reduce((prev, curr) => [prev, ', ', curr])}
     </div>
  }
}

如果没有第二个参数,reduce()它将从索引1而不是0开始,并且React非常满意嵌套数组。

如评论中所述,您只想将它​​用于至少包含一项的数组,因为reduce()没有第二个参数将抛出一个空数组。通常,这应该不成问题,因为无论如何,对于空数组,您都希望显示一条自定义消息,例如“ this is empty”。

打字稿更新

您可以在Typescript中使用此参数(不带type-unsafe any),其React.ReactNode类型参数为.map()

class List extends React.Component {
  render() {
     <div>
        {this.props.data
          .map<React.ReactNode>(t => <span>{t}</span>)
          .reduce((prev, curr) => [prev, ', ', curr])}
     </div>
  }
}

3
If the array is empty and no initialValue was provided, TypeError would be thrown.。因此它不适用于空数组。
尤金·克雷维涅茨

6
还要注意,这递归嵌套了prev数组。例如[1, 2, 3, 4]成为[[[1,",",2],",",3],",",4]
塔林

2
@Tamlyn:您认为我最初在答案中提到您的观点(“ React非常满意嵌套数组”)还是我应该详细说明?
Maarten ter Horst

1
有人使这个解决方案可以与React + TypeScript一起使用吗?
马特·戴尔

1
@Jstuff我不得不使用任何东西。.reduce((prev: JSX.Element, current: JSX.Element): any => [prev, (<span>&nbsp;</span>), current])
马特·戴尔

26

您可以使用reduce合并数组的多个元素:

React.createClass({
  render() {
     <div>
        this.props.data
        .map(t => <span>t</span>)
        .reduce((accu, elem) => {
            return accu === null ? [elem] : [...accu, ',', elem]
        }, null)
     </div>
  }
})

这会使用null初始化累加器,因此我们可以将第一项包装在数组中。对于数组中的每个后续元素,我们使用构造一个新数组,其中包含所有先前的元素...-operator,添加分隔符,然后添加下一个元素。

Array.prototype.reduce()


2
谢谢,正是我所需要的。您可以通过将累加器初始化为空数组来删除空校验和三进制
Larry

7
@Larry如果删除了null检查和三进制,并通过[]作为初始值设定项,那么如何避免前导逗号?['a'].reduce((a, e) => [...a, ',', e],[])产量[",", "a"]。除非数组为空,否则不传递任何初始化器都行不通,在这种情况下,它将返回TypeError。
盖伊

@Guy,您绝对正确-我的错误是我将值与空格连接在一起,并且在呈现的输出中缺少空跨度
Larry

12

使用React 16更新:现在可以直接渲染字符串,因此您可以通过删除所有无用的<span>标签来简化代码。

const list = ({ data }) => data.reduce((prev, curr) => [ prev, ', ', curr ]);

8

接受的答案实际上返回一个数组数组,因为prev每次都会是一个数组。React足够聪明,可以完成这项工作,但是将来很容易引起问题,例如在为每个映射结果提供键时会破坏Reacts差异算法。

这项新React.Fragment功能使我们能够以一种易于理解的方式执行此操作,而不会出现潜在的问题。

class List extends React.Component {
  render() {
     <div>
        {this.props.data
          .map((t, index) => 
            <React.Fragment key={index}>
              <span> {t}</span> ,
            </React.Fragment>
          )
      </div>
  }
}

有了React.Fragment我们,我们可以简单地将分隔符,放在返回的HTML的外部,而React不会抱怨。


2
很棒的解决方案,但您需要删除数组最后一个元素的逗号
indapublic

您始终可以使用车床和索引来解决该问题。
Jstuff

2
您可以使用此修改删除最后一个逗号:<React.Fragment key = {index}> <span> {t} </ span> {index === this.props.data.length-1?'':','} </React.Fragment>
JohnP

7

<span>{t}</span>你返回是一个对象,而不是字符串。检查有关它的React文档https://facebook.github.io/react/docs/jsx-in-depth.html#the-transform

通过使用.join()从中返回的数组map,您可以连接对象数组。[object Object], ...

您可以将逗号放在内,<span></span>以使其按照您希望的方式呈现。

  render() {
    return (
      <div>
        { this.props.data.map(
            (t,i) => <span>{t}{ this.props.data.length - 1 === i ? '' : ','} </span>
          )
        }
      </div>
    )
  }

样本: https : //jsbin.com/xomopahalo/edit?html,js,输出


3

我的变体:

{this.props.data
    .map(item => <span>{item}</span>)
    .map((item, index) => [index > 0 && ', ', item ])}

2

如果我只想呈现以逗号分隔的组件数组,通常会觉得reduce太冗长。在这种情况下,较短的解决方案是

{arr.map((item, index) => (
  <Fragment key={item.id}>
    {index > 0 && ', '}
    <Item {...item} />
  </Fragment>
))}

{index > 0 && ', '} 将在所有数组项(第一个数组项除外)的前面呈现一个逗号,后跟一个空格。

如果要用其他东西将倒数第二个项目和最后一个项目分开,请说字符串' and ',则可以替换{index > 0 && ', '}

{index > 0 && index !== arr.length - 1 && ', '}
{index === arr.length - 1 && ' and '}

2

使用es6,您可以执行以下操作:

const joinComponents = (accumulator, current) => [
  ...accumulator, 
  accumulator.length ? ', ' : '', 
  current
]

然后运行:

listComponents
  .map(item => <span key={item.id}> {item.t} </span>)
  .reduce(joinComponents, [])

1

使用嵌套数组将“,”放在外面。

  <div>
      {this.props.data.map((element, index) => index == this.props.data.length - 1 ? <span key={index}>{element}</span> : [<span key={index}>{element}</span>, ", "])}
  </div>

通过将数据保存到数组并修改最后一个元素而不是始终检查其最后一个元素来对其进行优化。

  let processedData = this.props.data.map((element, index) => [<span key={index}>{element}</span>, ", "])
  processedData [this.props.data.length - 1].pop()
  <div>
      {processedData}
  </div>

0

这对我有用:

    {data.map( ( item, i ) => {
                  return (
                      <span key={i}>{item.propery}</span>
                    )
                  } ).reduce( ( prev, curr ) => [ prev, ', ', curr ] )}

0

如Pith所述,React 16允许您直接使用字符串,因此不再需要将字符串包装在span标签中。基于Maarten的答案,如果您还想立即处理自定义消息(并避免在空数组上引发错误),则可以在数组的length属性上使用三元if语句来引导操作。可能看起来像这样:

class List extends React.Component {
  const { data } = this.props;

  render() {
     <div>
        {data.length
          ? data.reduce((prev, curr) => [prev, ', ', curr])
          : 'No data in the array'
        }
     </div>
  }
}

0

这应该返回一个平面数组。通过提供初始的空数组来处理具有不可迭代的第一个对象的情况,并从结果中过滤出不需要的第一个逗号

[{}, 'b', 'c'].reduce((prev, curr) => [...prev, ', ', curr], []).splice(1) // => [{}, 'b', 'c']

0

我是唯一认为这里的答案中有很多不必要的散布和嵌套的人吗?简明扼要的观点是肯定的,但这为规模问题或React改变了它们处理嵌套数组/片段的方式留有余地。

const joinJsxArray = (arr, joinWith) => {
  if (!arr || arr.length < 2) { return arr; }

  const out = [arr[0]];
  for (let i = 1; i < arr.length; i += 1) {
    out.push(joinWith, arr[i]);
  }
  return out;
};

// render()
<div>
  {joinJsxArray(this.props.data.map(t => <span>t</span>), ', ')}
</div>

一个数组,没有嵌套。也没有性感的方法链接,但是,如果您发现自己经常这样做,则始终可以将其添加到数组原型中,或者将其包装在需要映射回调的函数中,以一次性完成所有操作。


0
function YourComponent(props) {

  const criteria = [];

  if (something) {
    criteria.push(<strong>{ something }</strong>);
  }

  // join the jsx elements with `, `
  const elements = criteria.reduce((accu, elem) => {
    return accu === null ? [elem] : [...accu, ', ', elem]
  }, null);

  // render in a jsx friendly way
  return elements.map((el, index) => <React.Fragment key={ index }>{ el }</React.Fragment> );

}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.