Using react-virtualized to implement a long list of images with dynamic height

Using react-virtualized to implement a long list of images with dynamic height

Virtual list is a technology that renders a portion of the data in a long list according to the visible area of ​​the scroll container element. Virtual lists are a common optimization for long list scenarios. After all, few people render hundreds of sub-elements in a list. It is only necessary to render the elements in the visible area when the scroll bar scrolls horizontally or vertically.

Problems encountered during development

1. The pictures in the long list should maintain the same proportion as the original pictures. When the width remains unchanged during vertical scrolling, the height of each picture is dynamic. When the height of the list item changes, it will affect the position information of the list item and all subsequent list items.

2. The image width and height can only be obtained after the image is loaded.

Solution

We use the list component in react-virtualized, the official example

import React from 'react';
import ReactDOM from 'react-dom';
import {List} from 'react-virtualized';

// List data as an array of strings
const list = [
  'Brian Vaughn',
  // And so on...
];

function rowRenderer({
  key, // Unique key within array of rows
  index, // Index of row within collection
  isScrolling, // The List is currently being scrolled
  isVisible, // This row is visible within the List (eg it is not an overscanned row)
  style, // Style object to be applied to row (to position it)
}) {
  return (
    <div key={key} style={style}>
      {list[index]}
    </div>
  );
}

// Render your list
ReactDOM.render(
  <List
    width={300}
    height={300}
    rowCount={list.length}
    rowHeight={20}
    rowRenderer={rowRenderer}
  />,
  document.getElementById('example'),
); 

Where rowHeight is the height of each row. You can pass in a fixed height or a function. Each time the height of a child element changes, the recomputeRowHeights method needs to be called to recalculate the row height and offset after specifying the index.

Specific implementation

const ImgHeightComponent = ({ imgUrl, onHeightReady, height, width }) => {
  const [style, setStyle] = useState({
    height,
    width,
    display: 'block',
  })
  const getImgWithAndHeight = (url) => {
    return new Promise((resolve, reject) => {
      var img = new Image()
      // Change the src of the image
      img.src = url
      let set = null
      const onload = () => {
        if (img.width || img.height) {
          //Image loading completed clearInterval(set)
          resolve({ width: img.width, height: img.height })
        }
      }
      set = setInterval(onload, 40)
    })
  }

  useEffect(() => {
    getImgWithAndHeight(imgUrl).then((size) => {
      const currentHeight = size.height * (width / size.width)
      setStyle({
        height: currentHeight,
        width: width,
        display: 'block',
      })
      onHeightReady(currentHeight)
    })
  }, [])
  return <img src={imgUrl} alt='' style={style} />
}

First, write a component to obtain the image height, obtain and calculate the height through a timed loop detection and pass it to the parent component.

import React, { useState, useEffect, useRef } from 'react'
import styles from './index.scss'
import { AutoSizer } from 'react-virtualized/dist/commonjs/AutoSizer'
import { List } from 'react-virtualized/dist/commonjs/List'

export default class DocumentStudy extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      list: [], 
      heights: [],
      autoWidth:900,
      autoHeight: 300
    }
  }

  handleHeightReady = (height, index) => {
    this.setState(
      (state) => {
        const flag = state.heights.some((item) => item.index === index)
        if (!flag) {
          return {
            heights: [
              ...state.heights,
              {
                index,
                height,
              },
            ],
          }
        }
        return {
          heights: state.heights,
        }
      },
      () => {
        this.listRef.recomputeRowHeights(index)
      },
    )
  }

  getRowHeight = ({ index }) => {
    const row = this.state.heights.find((item) => item.index === index)
    return row ? row.height : this.state.autoHeight
  }

  renderItem = ({ index, key, style }) => {
    const { list, autoWidth, autoHeight } = this.state
    if (this.state.heights.find((item) => item.index === index)) {
      return (
        <div key={key} style={style}>
          <img src={list[index].imgUrl} alt='' style={{width: '100%'}}/>
        </div>
      )
    }

    return (
      <div key={key} style={style}>
        <ImgHeightComponent
          imgUrl={list[index].imgUrl}
          width={autoWidth}
          height={autoHeight}
          onHeightReady={(height) => {
            this.handleHeightReady(height, index)
          }}
        />
      </div>
    )
  }

  render() {
    const { list } = this.state
    return (
      <>
        <div style={{ height: 1000 }}>
          <AutoSizer>
            {({ width, height }) => (
              <List
                ref={(ref) => (this.listRef = ref)}
                width={width}
                height={height}
                overscanRowCount={10}
                rowCount={list.length}
                rowRenderer={this.renderItem}
                rowHeight={this.getRowHeight}
              />
            )}
          </AutoSizer>
        </div>
      </>
    )
  }
}

The parent component collects the heights of all images through the handleHeightReady method, and calls the recomputeRowHeights method of the List component every time the height changes to notify the component to recalculate the height and offset. At this point, the problems encountered have basically been solved.

Actual Results

summary

Currently, we only use react-virtualized to implement the long list of images. The specific internal implementation of react-virtualized needs further study.

The above is the details of using react-virtualized to implement a long list of dynamic images. For more information about react virtualized long lists, please pay attention to other related articles on 123WORDPRESS.COM!

You may also be interested in:
  • Example analysis of the usage of ScrollView component carousel and ListView rendering list component in React Native
  • React mobile terminal implements the sample code of swiping left to delete the list
  • React Native custom pull-down refresh pull-up loaded list example
  • React Native indexed city list component example code
  • React implements clicking to delete the corresponding item in the list

<<:  Tutorial on installing php5, uninstalling php, and installing php7 on centos

>>:  How to create a new user in CentOS and enable key login

Recommend

Docker memory monitoring and stress testing methods

The Docker container that has been running shows ...

Web design and production test questions and reference answers

<br />Web Design and Production Test Part I ...

AsyncHooks asynchronous life cycle in Node8

Async Hooks is a new feature of Node8. It provide...

Native js implements shopping cart logic and functions

This article example shares the specific code of ...

JS uses map to integrate double arrays

Table of contents Preface Simulating data Merged ...

How to install mysql on centos and set up remote access

1. Download the mysql repo source $ wget http://r...

A simple method to be compatible with IE6's min-width and min-height

If a website is widescreen, you drag the browser ...

Detailed explanation of the sticky position attribute in CSS

When developing mobile apps, you often encounter ...

How to use dynamic parameters and calculated properties in Vue

1. Dynamic parameters Starting from 2.6.0, you ca...

How to modify create-react-app's configuration without using eject

1. Why is eject not recommended? 1. What changes ...

js to realize web music player

This article shares simple HTML and music player ...

HTML Table Tag Tutorial (47): Nested Tables

<br />In the page, typesetting is achieved b...

5 cool and practical HTML tags and attributes introduction

In fact, this is also a clickbait title, and it c...