반복되는 React 요소를 어떻게 렌더링 할 수 있습니까?


81

ReactJS에서 반복되는 요소를 렌더링하는 코드를 작성했지만 얼마나 못 생겼는지 싫어합니다.

render: function(){
  var titles = this.props.titles.map(function(title) {
    return <th>{title}</th>;
  });
  var rows = this.props.rows.map(function(row) {
    var cells = [];
    for (var i in row) {
      cells.push(<td>{row[i]}</td>);
    }
    return <tr>{cells}</tr>;
  });
  return (
    <table className="MyClassName">
      <thead>
        <tr>{titles}</tr>
      </thead>
      <tbody>{rows}</tbody>
    </table>
  );
} 

이것을 달성하는 더 좋은 방법이 있습니까?

( for템플릿 코드 또는 유사한 접근 방식 내에 루프 를 포함하고 싶습니다 .)



3
예, 내가 원하는 것은 그치지 만 받아 들여지는 대답은 이미 작성중인 추악한 코드와 거의 같습니다. 더 나은 방법이 있어야합니다 ...
fadedbee 2014 년

나는이 의지 도움말 희망 stackoverflow.com/a/37600679/1785635을
abhirathore2006

답변:


130

중괄호 안에 표현식을 넣을 수 있습니다. 컴파일 된 JavaScript에서 forJSX 구문 내 에서 루프가 불가능한 이유에 주목하십시오 . JSX는 함수 호출과 설탕 함수 인수에 해당합니다. 표현식 만 허용됩니다.

(또한 : key루프 내부에서 렌더링 된 구성 요소 에 속성 을 추가해야합니다 .)

JSX + ES2015 :

render() {
  return (
    <table className="MyClassName">
      <thead>
        <tr>
          {this.props.titles.map(title =>
            <th key={title}>{title}</th>
          )}
        </tr>
      </thead>
      <tbody>
        {this.props.rows.map((row, i) =>
          <tr key={i}>
            {row.map((col, j) =>
              <td key={j}>{col}</td>
            )}
          </tr>
        )}
      </tbody>
    </table>
  );
} 

자바 스크립트 :

render: function() {
  return (
    React.DOM.table({className: "MyClassName"}, 
      React.DOM.thead(null, 
        React.DOM.tr(null, 
          this.props.titles.map(function(title) {
            return React.DOM.th({key: title}, title);
          })
        )
      ), 
      React.DOM.tbody(null, 
        this.props.rows.map(function(row, i) {
          return (
            React.DOM.tr({key: i}, 
              row.map(function(col, j) {
                return React.DOM.td({key: j}, col);
              })
            )
          );
        })
      )
    )
  );
} 

좋은 캐치. 나는 상단에 누락 된 괄호를 추가로 전환 forA와 map. 각 데이터 구조에 데이터가 무엇인지 모르기 때문에 행이 배열이라고 가정하고 key. 어레이에서 데이터를 추가 / 제거하면 불필요한 다시 렌더링이 발생합니다. key데이터를 고유하게 식별하고 배열의 순서 및 / 또는 크기에 의존하지 않는 값으로 전환해야합니다 .
Ross Allen

@ssorallen 귀하의 답변에 감사드립니다. 답변을 수락하기 전에 더 좋은 방법이 있다면이 질문을 며칠 동안 열어 두겠습니다. 내 문제는 JSX에 비 표현 이스케이프, for for루프 및 이와 유사한 것이 없으며 루프에 대한 템플릿 구문이 없다는 것입니다.
fadedbee 2014 년

1
@chrisdew JSX는 템플릿 언어가 아니며 평범한 오래된 JavaScript의 구문 설탕입니다. 템플릿 언어에서 기대하는 것과 같은 연산자를 얻지 못할 것입니다. 이 답변의 코드를 라이브 JSX 컴파일러 에 붙여 넣어 수행하는 작업과 for루프가 불가능한 이유를 이해 하십시오.
Ross Allen

각 행에 onClick 이벤트를 추가하고 행 항목을 함수에 전달할 수 있습니까? 나는 이와 같은 것을 시도하고 있지만 Uncaught TypeError : Cannot read property 'clickHandler'of undefined clickHandler () {console.log ( 'on click row'); } <tbody> {this.props.rows.map (function (row, i) {return (<tr key = {i} onClick = this.clickHandler ()> {row.map (function (col, j) {return <td key = {j}> {col} </ td>;})} </ tr>);})} </ tbody>
Kiran

맵 메서드에 .bind (this)를 추가 한 다음 메서드가 각 행에 관여하는 것은 신경 쓰지 마십시오. 감사합니다.
Kiran

13

Ross Allen의 답변을 확장하기 위해 ES6 화살표 구문을 사용하는 약간 더 깨끗한 변형이 있습니다.

{this.props.titles.map(title =>
  <th key={title}>{title}</th>
)}

JSX 부분이 분리되어 있다는 장점이있어 (아니오 return또는 ;) 주위에 루프를 더 쉽게 배치 할 수 있습니다.


13

반복 불가능한 배열Array(3) 을 생성 하므로 Array 메서드 를 사용할 수 있도록 채워야합니다 . "변환"하는 방법은 Array-brackets 내부에서 그것을 파괴하는 것입니다. 이것은 Array가 다음과 같은 값 으로 채워지도록 "강제"하는 것입니다.mapundefinedArray(N).fill(undefined)

<table>
    { [...Array(3)].map((_, index) => <tr key={index}/>) }
</table>

또 다른 방법은 Array를 사용하는 것입니다 fill().

<table>
    { Array(3).fill(<tr/>) }
</table>

위의 예제와 문제의 부족 key이다 소품, 필수 .
(반복자를 사용하는 것 index같은 key권장하지 않습니다)


중첩 노드 :

const tableSize = [3,4]
const Table = (
    <table>
        <tbody>
        { [...Array(tableSize[0])].map((tr, trIdx) => 
            <tr key={trIdx}> 
              { [...Array(tableSize[1])].map((a, tdIdx, arr) => 
                  <td key={trIdx + tdIdx}>
                  {arr.length * trIdx + tdIdx + 1}
                  </td>
               )}
            </tr>
        )}
        </tbody>
    </table>
);

ReactDOM.render(Table, document.querySelector('main'))
td{ border:1px solid silver; padding:1em; }
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<main></main>


2
렌더링 함수에서 루프 내부를 반복 할 수 있도록 최소 2 시간을 보냈습니다. 감사. 당신은 내 하루를 구했습니다.
Shwe

2
지도를 사용하는 대신 이것을 할 수 없습니까? Array.from({length: 5}, (value, index) => <tr />)
creativehandle

2

함수형 프로그래밍의 정신으로 추상화를 사용하여 구성 요소 작업을 좀 더 쉽게 만들어 보겠습니다.

// converts components into mappable functions
var mappable = function(component){
  return function(x, i){
    return component({key: i}, x);
  }
}

// maps on 2-dimensional arrays
var map2d = function(m1, m2, xss){
  return xss.map(function(xs, i, arr){
    return m1(xs.map(m2), i, arr);
  });
}

var td = mappable(React.DOM.td);
var tr = mappable(React.DOM.tr);
var th = mappable(React.DOM.th);

이제 다음과 같이 렌더링을 정의 할 수 있습니다.

render: function(){
  return (
    <table>
      <thead>{this.props.titles.map(th)}</thead>
      <tbody>{map2d(tr, td, this.props.rows)}</tbody>
    </table>
  );
}

jsbin


map2d의 대안은 카레 맵 기능이지만 사람들은 카레를 피하는 경향이 있습니다.


이러한 함수는 개발자에게 key속성 을 지정할 기회를주지 않습니다 . 인덱스를 사용하면 요소를 추가 / 제거하면 변경되지 않았을 수있는 객체에 대해 강제로 다시 렌더링됩니다.
Ross Allen

사실이지만 95 %의 경우 인덱스 기반 키로 충분합니다. 나는 다소 드문 예외에 대해 조금 벗어나고 싶습니다.
Brigand

동의합니다. 필요한 경우 특정 수준에서 키가 고유한지 확인하는 것이 쉽습니다.
Ryan Ore

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.