javascript - React table slow loading when displaying img rows - Stack Overflow

I am new to React. I am just trying to build a table of data ing from an API which I got it fetching. B

I am new to React. I am just trying to build a table of data ing from an API which I got it fetching. But now I want to render the data into a table.

My issue is that one of the columns is a logo that es from a URL index.php?Action=GetLogo&id=51. The number of results is more than 300. Even though I am already using pagination the table rendering is slow, particularly the logo column. All the data gets loaded, but I can see each logo being rendered row by row, giving the user a slow experience.

Is there any way how React can approach to solve this issue? Someone please point me in the right direction how to tackle this.

Thanks everyone.

Update Someone has advised me to use a sync/await function to load the images. Then I am updating the code. However my main issue is still with me: loading the data particularly the logo column. All the data gets rendered, but not the logo column, then each logo starts to render one by one looking very slow. I thought the async/await function would alleviate that.

    import React from 'react';
    import ReactDOM from 'react-dom';
    import FormData from 'form-data';

    class FilterableSupplierTable extends React.Component {
        constructor(props) {
            super(props);
            this.state = {
                suppliers: []
            }
        }

        ponentDidMount() {
            let formData = new FormData();
            formData.append('AjaxMethodName', 'GetSuppliers');
            const options = {
                method: 'POST',
                headers: {
                    'Accept': '*/*'
                },
                body: formData
            };
            fetch(`?Model=route_to_controller`, options)
                .then(response => response.json())
                .then(data => {
                    this.setState({ suppliers: JSON.parse(data.response_data) })
                });
        }

        async getLogos(suppliers) {
            return await Promise.all(
                suppliers.map(async supplier => {
                    supplier.new_logo = !!supplier.has_logo ?
                        <img style={{maxWidth: "100px"}} src={supplier.logo} alt={supplier.supplier_id} /> :
                        <i className="icon icon-warning no_logo">&nbsp;No Logo</i>;
                    return supplier;
                });
            );
        }

        render() {
            const rows = [];
            const suppliers = this.state.suppliers;
            this.getLogos(suppliers)
                .then(results => {
                    results.map(supplier => {
                        rows.push(
                            <tr>
                                {/* supplier.logo is index.php?Action=GetLogo&id=51, etc */}
                                <td><img src={supplier.new_logo} /></td>
                                <td>{supplier.name}</td>
                            </tr>
                        );
                    });
                });

            return (
                <table>
                    <thead>
                        <tr>
                            <th colSpan="4">Suppliers</th>
                        </tr>
                        <tr>
                            <th>Logo</th>
                            <th>Name</th>
                        </tr>
                    </thead>
                    <tbody>{rows}</tbody>
                </table>
            );
        }
    }
    ReactDOM.render(
        <FilterableSupplierTable />,
        document.getElementById('suppliers_list')
    );

I am new to React. I am just trying to build a table of data ing from an API which I got it fetching. But now I want to render the data into a table.

My issue is that one of the columns is a logo that es from a URL index.php?Action=GetLogo&id=51. The number of results is more than 300. Even though I am already using pagination the table rendering is slow, particularly the logo column. All the data gets loaded, but I can see each logo being rendered row by row, giving the user a slow experience.

Is there any way how React can approach to solve this issue? Someone please point me in the right direction how to tackle this.

Thanks everyone.

Update Someone has advised me to use a sync/await function to load the images. Then I am updating the code. However my main issue is still with me: loading the data particularly the logo column. All the data gets rendered, but not the logo column, then each logo starts to render one by one looking very slow. I thought the async/await function would alleviate that.

    import React from 'react';
    import ReactDOM from 'react-dom';
    import FormData from 'form-data';

    class FilterableSupplierTable extends React.Component {
        constructor(props) {
            super(props);
            this.state = {
                suppliers: []
            }
        }

        ponentDidMount() {
            let formData = new FormData();
            formData.append('AjaxMethodName', 'GetSuppliers');
            const options = {
                method: 'POST',
                headers: {
                    'Accept': '*/*'
                },
                body: formData
            };
            fetch(`?Model=route_to_controller`, options)
                .then(response => response.json())
                .then(data => {
                    this.setState({ suppliers: JSON.parse(data.response_data) })
                });
        }

        async getLogos(suppliers) {
            return await Promise.all(
                suppliers.map(async supplier => {
                    supplier.new_logo = !!supplier.has_logo ?
                        <img style={{maxWidth: "100px"}} src={supplier.logo} alt={supplier.supplier_id} /> :
                        <i className="icon icon-warning no_logo">&nbsp;No Logo</i>;
                    return supplier;
                });
            );
        }

        render() {
            const rows = [];
            const suppliers = this.state.suppliers;
            this.getLogos(suppliers)
                .then(results => {
                    results.map(supplier => {
                        rows.push(
                            <tr>
                                {/* supplier.logo is index.php?Action=GetLogo&id=51, etc */}
                                <td><img src={supplier.new_logo} /></td>
                                <td>{supplier.name}</td>
                            </tr>
                        );
                    });
                });

            return (
                <table>
                    <thead>
                        <tr>
                            <th colSpan="4">Suppliers</th>
                        </tr>
                        <tr>
                            <th>Logo</th>
                            <th>Name</th>
                        </tr>
                    </thead>
                    <tbody>{rows}</tbody>
                </table>
            );
        }
    }
    ReactDOM.render(
        <FilterableSupplierTable />,
        document.getElementById('suppliers_list')
    );
Share edited Jan 4, 2021 at 7:24 GalAbra 5,1385 gold badges25 silver badges43 bronze badges asked Apr 12, 2020 at 10:05 ivantxoivantxo 6395 gold badges18 silver badges37 bronze badges 11
  • sometimes the size of the images can increase load time in dev enviroment are you certain the images are web optimized? – Hadi Pawar Commented Apr 12, 2020 at 10:15
  • 'Lagging' can mean more things. Try using await or a Suspense block – Adrian Pascu Commented Apr 12, 2020 at 12:05
  • @AdrianPascu I will check that thanks I have also updated the title. – ivantxo Commented Apr 12, 2020 at 22:06
  • Could it be a case where these images are extremely 'heavy'? High resolution and also not optimized which can lead to large filesizes to render in the table ponent? – Malakai Commented Apr 12, 2020 at 22:20
  • @AdrianPascu. Can you give me an example how can I use those blocks? – ivantxo Commented Apr 13, 2020 at 2:30
 |  Show 6 more ments

2 Answers 2

Reset to default 7 +50

Your issue can be solved with a ponent that updates a "global loading state".

Only after all images have updated that they finished loading, they bee visible together:

function MyImage(props) {
  const onLoad = () => {
    props.onLoad();
  };

  return (
    <div>
      {props.isCurrentlyLoading && <div>Loading</div>}
      <img
        src={props.src}
        onLoad={onLoad}
        style={
          props.isCurrentlyLoading
            ? { width: "0", height: "0" } // You can also use opacity, etc.
            : { width: 100, height: 100 }
        }
      />
    </div>
  );
}

function ImagesBatch() {
  const [loadedImagesCounter, setLoadedImagesCounter] = useState(0);
  const [isAllLoaded, setIsAllLoaded] = useState(false);

  const updateLoading = () => {
    if (loadedImagesCounter + 1 === imagesUrls.length) {
      setIsAllLoaded(true);
    }
    setLoadedImagesCounter(prev => prev + 1);
  };

  return (
    <div>
      {imagesUrls.map((url, index) => {
        return (
          <MyImage
            key={url}
            src={url}
            index={index + 1}
            isCurrentlyLoading={!isAllLoaded}
            onLoad={updateLoading}
          />
        );
      })}
    </div>
  );
}

You can check the full code here (preferably with an open console), where I used an arbitrary ~6MB image, as an example.

I think you got your issues resolved. But, apart from that I suggest you checkout React Virtualized, https://github./bvaughn/react-virtualized

Hope this helps some day.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1742295317a4416999.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信