如何在 React 中解决这个渲染难题?

Avatar of Burke Holland
Burke Holland

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 200 美元的免费额度!

欢迎,React 爱好者和像我这样的业余爱好者!今天我有一个难题要考考大家。

假设您想以两列结构渲染项目列表。每个项目都是一个单独的组件。例如,假设我们有一个专辑列表,并且希望将其渲染为一个全页面两列列表。每个“专辑”都是一个 React 组件。

滚动渲染问题

现在假设您正在使用的 CSS 框架要求您渲染出这样的两列布局…

<div class="columns">
  <div class="column"> Column 1 </div>
  <div class="column"> Column 2 </div>
<div class="columns">

这意味着为了正确渲染专辑,您必须打开一个 columns div 标签,渲染两个专辑,然后关闭该标签。您一遍又一遍地这样做,直到所有专辑都渲染出来。

我通过将集合分成块并在单独的渲染函数中以条件方式渲染每个其他专辑来解决此问题。该渲染函数仅针对每个其他项目调用。

class App extends Component { 
  state = {albums: [] }

  async componentDidMount() { 
    let data = Array.from(await GetAlbums());
    this.setState({ albums: data } ); 
  } 

  render() { 
    return (
      <section className="section">
        {this.state.albums.map((album, index) => {
          // use the modulus operator to determine even items return index % 2 ?
          this.renderAlbums(index) : '';
        })}
      </section> 
    )
  }

  renderAlbums(index) { 
    // two albums at a time - the current and previous item
    let albums = [this.state.albums[index - 1], this.state.albums[index]]; 
    
    return (
      <div className="columns" key={index}>
        {albums.map(album => {
          return (
            <Album album={album} />
          );
        })}
      </div>
    );
  }
}

查看完整项目

另一种方法是将专辑数组分解成一个二维数组并对其进行迭代。下面的第一个突出显示的代码块将数组拆分。第二个是大大简化的渲染逻辑。

class App extends Component { 
  state = {albums: []}
  
  async componentDidMount() { 
    let data = Array.from(await GetAlbums());
    
    // split the original array into a collection of two item sets
    data.forEach((item, index) => {
      if (index % 2) {
        albums.push([data[index - 1], data[index]]);
      }
    });

    this.setState({
      albums: albums
    });
  } 

  render() {
    return ( 
      <section className="section">
        {this.state.albums.map((album, index) => { 
          return ( 
            <div className="columns">
              <Album album={album[0]}></Album> 
              <Album album={album[1]}></Album> 
            </div> 
          ) 
        })}
      </section> 
    ) 
  } 
}

查看完整项目

这使 JSX 清理了很多,但现在我冗余地输入了 Album 组件,这感觉不太对。

Sarah Drasner 指出我甚至没有考虑这里更重要的场景之一,那就是未知底部场景。

未知底部

我上面提供的两种解决方案都假设从 fetch 收到的结果集是最终的。但如果它不是呢?

如果我们正在从服务器流式传输数据(类似于 RxJs 样式),并且我们不知道我们将收到多少次结果集,也不知道给定集中有多少个项目。这确实使事情变得复杂,并且完全破坏了提议的解决方案。实际上,我们可以继续说这两个解决方案都不是理想的,因为它们无法扩展到这种用例。

我觉得这里最简单的解决方案是在 CSS 中修复它。让 CSS 以预期的的方式处理布局。我仍然认为查看如何使用 JSX 执行此操作很重要,因为现实世界中有人每天都必须处理这样的恶作剧。需求并不总是我们希望它们成为的样子。

您将如何做?

我的问题就是这样——您将如何做到这一点?是否有更简洁、更高效的方法?如何才能做到这一点,使其能够扩展到未知底部?好奇的人(尤其是我的)很想了解。