반복되는 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.