React table 显示 img 行时加载缓慢
React table slow loading when displaying img rows
我是 React 新手。我只是想构建一个 table 的数据,这些数据来自我获取的 API。但是现在我想将数据渲染成table。
我的问题是其中一列是来自 URL index.php?Action=GetLogo&id=51
的徽标。结果数超过 300。尽管我已经在使用分页,但 table 呈现速度很慢,尤其是 logo
列。所有数据都已加载,但我可以看到每个徽标都在逐行呈现,给用户带来缓慢的体验。
React 有什么办法可以解决这个问题吗?有人请指出正确的方向如何解决这个问题。
谢谢大家
更新
有人建议我使用 sync/await 函数来加载图像。然后我正在更新代码。但是,我的主要问题仍然存在:加载数据,尤其是徽标列。所有数据都被渲染,但徽标列没有渲染,然后每个徽标开始一个一个地渲染,看起来非常慢。我认为 async/await
函数可以缓解这种情况。
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: []
}
}
componentDidMount() {
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"> 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')
);
您的问题可以通过更新 "global loading state".
的组件来解决
只有在 所有 图像更新完成加载后,它们才会一起显示:
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>
);
}
您可以查看完整代码 here(最好使用打开的控制台),我在其中使用了任意 ~6MB 图像作为示例。
我想你的问题已经解决了。但是,除此之外,我建议您查看 React Virtualized,https://github.com/bvaughn/react-virtualized
希望这对某一天有所帮助。
我是 React 新手。我只是想构建一个 table 的数据,这些数据来自我获取的 API。但是现在我想将数据渲染成table。
我的问题是其中一列是来自 URL index.php?Action=GetLogo&id=51
的徽标。结果数超过 300。尽管我已经在使用分页,但 table 呈现速度很慢,尤其是 logo
列。所有数据都已加载,但我可以看到每个徽标都在逐行呈现,给用户带来缓慢的体验。
React 有什么办法可以解决这个问题吗?有人请指出正确的方向如何解决这个问题。
谢谢大家
更新
有人建议我使用 sync/await 函数来加载图像。然后我正在更新代码。但是,我的主要问题仍然存在:加载数据,尤其是徽标列。所有数据都被渲染,但徽标列没有渲染,然后每个徽标开始一个一个地渲染,看起来非常慢。我认为 async/await
函数可以缓解这种情况。
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: []
}
}
componentDidMount() {
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"> 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')
);
您的问题可以通过更新 "global loading state".
的组件来解决只有在 所有 图像更新完成加载后,它们才会一起显示:
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>
);
}
您可以查看完整代码 here(最好使用打开的控制台),我在其中使用了任意 ~6MB 图像作为示例。
我想你的问题已经解决了。但是,除此之外,我建议您查看 React Virtualized,https://github.com/bvaughn/react-virtualized
希望这对某一天有所帮助。