所以我正在制作一个带有项目列表的导航栏,每个项目都有一个图像和一个文本相关联。我使用react-virtualized list,因此基本上我不需要加载所有项目:
length
属性来显示它有多少个孩子(我使用docuri表示ids)我决定去做这样的事情:
export default abstract class LibraryItemComponent extends React.Component {
protected image: HTMLImageElement;
abstract loadImage (id: string, img: HTMLImageElement): void;
abstract loadItem (id: string): void;
abstract unloadItem (): void;
componentDidMount() {
this.loadItem(this.props.id);
this.loadImage(this.props.id, this.image);
}
componentWillReceiveProps (nextProps: LibraryItemComponentProps) {
if (nextProps.id !== this.props.id) {
if (nextProps.id) {
this.loadItem(nextProps.id);
this.loadImage(nextProps.id, this.image);
}
}
}
render ()
return <div >
<div className="item-image"><img src={BLANK_IMAGE} ref={(ref) => this.image = ref} data-doc-id={this.props.id} /></div>
<div className="item-props">
<div className="item-name">
{this.renderHeader()}
</div>
<div className="item-subtitle">
{this.renderSubtitle()}
</div>
</div>
</div>
}
loadImage
实现如下所示:
loadImage(id: string, img: HTMLImageElement): void {
MediaManager.getInstance().load(id, this.image);
}
来自load
的{{1}}类似于:
MediaManager
如您所见,加载函数首先加载blob,然后将图像附加到目标。加载并显示图像后,将解析承诺并继续承诺队列,加载下一个请求的图像。
然而,如果图像在仍然加载旧图像时接收到另一个id(因此它现在显示另一个项目标题),则此旧图像仍将(不必要地)加载并显示,仅在新图像加载后消失。
所以我在 load (docId: string, target: HTMLImageElement, watch = true): Promise<Blob> {
target.src = BLANK_IMAGE;
return this.queue.add(() => {
if (!this.shouldAttach(docId, target)) {
return Promise.resolve(new Blob());
}
return this.database.getAttachment(docId, size).catch(...).then((res: Blob) => {
if (!this.shouldAttach(docId, target)) {
return Promise.resolve(new Blob());
}
return this.attach(res, target, oldSrc);
});
});
}
attach (blob: Blob, target: HTMLImageElement, oldSrc: string): Promise<Blob> {
return new Promise((resolve) => {
if (!target || oldSrc !== target.src) {
return resolve(blob);
}
target.src = URL.createObjectURL(blob);
target.addEventListener('load', () => {
resolve(blob);
});
});
}
元素img
添加了一个属性,其中包含当前文档ID。然后,由于data-doc-id
shouldAttach
问题是,当组件收到新文档时,会调用 shouldAttach (docId: string, target: HTMLImageElement) {
if (!document.contains(target)) { // element has been removed from dom
return false;
}
const attr = target.getAttribute('data-doc-id');
if (attr && attr !== docId) { // we already changed document
return false;
}
return true;
}
,但如果队列为空,则立即调用ImageManager中的componentWillReceiveProps
函数,但load
没有尚未更新(因为componentWillReceiveProps)所以它将自行取消。因此,图像无法显示。我该如何解决这个问题?
第一个也很简单的想法就像是
data-doc-id
但是我想尽可能避免直接的DOM突变,因为根据我的经验,它可能会导致React的不稳定。
我正在考虑使用 this.image.setAttribute('data-doc-id', newDocId);
创建一个地图,但实施队列实施起来很难,而且我会失去可重用性
答案 0 :(得分:1)
我认为最好引用div并在其上添加<img>
。这将允许您在其ID更改时删除子项。这也允许您在将图像附加到div之前完全加载图像。 React并不关心,因为div不是React的关注点。