如何渲染重复的 React 元素?

Posted

技术标签:

【中文标题】如何渲染重复的 React 元素?【英文标题】:How can I render repeating React elements? 【发布时间】:2014-10-28 01:59:28 【问题描述】:

我已经编写了一些代码来渲染 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 循环,或者一些类似的方法。)

【问题讨论】:

你想要这样的东西吗? ***.com/questions/22876978/loop-inside-react-jsx 是的,这就是我想要的,但接受的答案与我已经在编写的丑陋代码大致相同。一定有更好的办法…… 我希望这会有所帮助***.com/a/37600679/1785635 【参考方案1】:

您可以将表达式放在大括号内。请注意编译后的 javascript 为什么在 JSX 语法中不可能出现 for 循环; 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>
  );
 

JavaScript

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

【讨论】:

不错的收获。我在顶部添加了缺少的括号并从for 切换到map。由于我不知道每个数据结构中的数据是什么,因此我假设行是数组,并将迭代的索引用于key。当从数组中添加/删除数据时,这将导致不必要的重新渲染。您应该将key 切换为唯一标识数据且不依赖于数组的顺序和/或大小的值。 @ssorallen 感谢您的回答。在接受您的回答之前,我会将这个问题留待几天,以防有更好的方法来做这件事。我认为我的问题是 JSX 似乎没有针对for 循环和类似的非表达式转义,也没有循环的模板语法。 @chrisdew JSX 不是模板语言,它是普通 JavaScript 的语法糖。您不会像从模板语言中所期望的那样获得运算符。尝试将此答案中的代码粘贴到实时 JSX compiler 中,以了解它在做什么以及为什么永远不可能使用 for 循环。 能否为每一行添加 onClick 事件并将行项目传递给函数?我正在尝试这样的事情,但我得到了 Uncaught TypeError: Cannot read property 'clickHandler' of undefined clickHandler() console.log('on click row'); this.props.rows.map(function(row, i) return ( row.map(function(col, j) return col; ) ); ) 没关系,我已将 .bind(this) 添加到 map 方法中,然后该方法涉及每一行。谢谢。【参考方案2】:

由于Array(3) 将创建un-iterable array,因此必须填充它以允许使用map 数组方法。一种“转换”的方式 是在 Array-brackets 中破坏它,这“强制”Array 填充undefined 值,与Array(N).fill(undefined) 相同

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

另一种方法是通过数组fill():

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

⚠️ 上面例子的问题是缺少key prop,即a must。 (不建议将迭代器的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 个小时才能够在渲染函数的循环内循环。谢谢。你拯救了我的一天。 你不能这样做而不是使用地图吗? Array.from(length: 5, (value, index) =&gt; &lt;tr /&gt;)【参考方案3】:

为了扩展 Ross Allen 的答案,这里有一个使用 ES6 箭头语法的更简洁的变体。

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

它的优点是 JSX 部分是隔离的(没有 return;),因此更容易在其周围放置循环。

【讨论】:

【参考方案4】:

这是 imo 最优雅的方式(使用 ES6)。用 7 个索引实例化你的空数组并在一行中映射:

Array.apply(null, Array(7)).map((i)=>
<Somecomponent/>
)

感谢 https://php.quicoto.com/create-loop-inside-react-jsx/

【讨论】:

不错!看来你也可以Array(...Array(10)).map((v, i) =&gt; &lt;SomeComponent /&gt;)【参考方案5】:

本着函数式编程的精神,让我们通过抽象让我们的组件更易于使用。

// 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 的替代方案是柯里化 map 函数,但人们倾向于回避柯里化。

【讨论】:

这些函数不会让开发人员有机会指定key 属性。使用索引意味着添加/删除元素将强制重新渲染可能未更改的对象。 是的,但 95% 的时间基于索引的键就足够了。对于一些罕见的例外情况,我宁愿稍微避开一点。 同意,如果有必要,确保密钥在任何给定级别都是唯一的很容易,我喜欢它。

以上是关于如何渲染重复的 React 元素?的主要内容,如果未能解决你的问题,请参考以下文章

React redux和React路由器,链接更改不会重新渲染视图[重复]

React前后端如何同构,防止重复渲染

如何使用 react-router-dom 卸载路由更改上的组件而不是重新渲染 [重复]

React:使用多个 onClick 重复渲染 JSX

列布局的React JSX条件渲染[重复]

这些条件在 React 渲染中不起作用 [重复]