マップと結合を使用して反応コンポーネントをレンダリングする方法


102

文字列の配列を表示するコンポーネントが1つあります。コードは次のようになります。

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]です。

オブジェクトを解釈して、レンダリングされる反応コンポーネントになる方法がわかりません。なにか提案を ?

回答:


147

簡単な解決策は、reduce()2番目の引数なしで、前の結果を広げることなく使用することです。

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

第二引数がなければ、reduce()なり、インデックス1から始まるの代わりに、0、およびネストされた配列と完全に満足して反応します。

コメントで述べたように、reduce()2つ目の引数がないと空の配列がスローされるため、これは少なくとも1つの項目を持つ配列にのみ使用する必要があります。とにかく、これは空の配列に対して「これは空です」のようなカスタムメッセージを表示したいので、これは問題にはなりません。

Typescriptの更新

これをTypescriptで(type-unsafeなしでanyReact.ReactNodeon型パラメーターを使用して使用できます.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.。空の配列では機能しません。
Eugene Krevenets

6
これにより、prev配列が再帰的にネストされることにも注意してください。たとえばに[1, 2, 3, 4]なり[[[1,",",2],",",3],",",4]ます。
タムリン2017

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
ありがとう、まさに私が必要としたもの。アキュムレータを空の配列として初期化することで、nullチェックと3項を削除できます
Larry

7
@ラリー、nullチェックと3項を削除し、初期化子として[]を渡す場合、先頭のコンマをどのように回避しますか?['a'].reduce((a, e) => [...a, ',', e],[])利回り[",", "a"]。初期化子を渡さないと、配列が空でない限り機能しません。その場合、TypeErrorが返されます。
Guy

@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の外にして文句を言わないであろう反応します。


2
素晴らしいソリューションですが、配列の最後の要素のカンマを削除する必要があります
indapublic

いつでもターナリーとインデックスを使用してそれを解決できます。
Jstuff

2
この変更で最後のカンマを削除できます:<React.Fragment key = {index}> <span> {t} </ span> {index === this.props.data.length-1?'': ''} </React.Fragment>
JohnP

7

<span>{t}</span>あなたが戻ってきているが、オブジェクトではなく文字列です。それについての反応ドキュメントをチェックしてください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,output


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 && ', '} 最初のものを除くすべての配列項目の前にスペースが続くコンマをレンダリングします。

あなたは最後から2番目の項目と他の何かによって、最後の1を分離したい場合は、文字列を言う' 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の回答に基づいて、カスタムメッセージもすぐに処理したい場合(および空の配列でエラーがスローされないようにする場合)は、配列の長さプロパティの三項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

これはフラット配列を返すはずです。最初の空の配列を提供することにより、反復不可能な最初のオブジェクトでsケースを処理し、不要な最初のカンマを結果からフィルタリングします

[{}, '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>

1つの配列、ネストなし。セクシーなメソッドチェーンもありませんが、これを頻繁に行う場合は、常に配列プロトタイプに追加するか、マッピングコールバックを受け取る関数にラップして、すべてを一度に実行できます。


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

}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.