我目前在Meteor中創建了一個自定義的React組件,用於將圖像添加到列表(以及稍後上傳它們)。但是,當我嘗試從列表中刪除圖像時,最後一個元素總是從GUI中刪除。起初,我認爲這只是使用錯誤索引進行刪除的一個簡單情況,但事實證明這不僅僅是一個例子。渲染的HTML與React組件不同步
這是我的ImageList
組件目前的樣子:
import React from 'react';
import Dropzone from 'react-dropzone';
import cloneDeep from 'lodash.clonedeep';
import { ImageItem } from './image-item.js';
export class ImagesList extends React.Component {
constructor(props) {
super(props);
this.values = this.props.images || [];
this.onDrop = this.onDrop.bind(this);
this.addImages = this.addImages.bind(this);
this.deleteImage = this.deleteImage.bind(this);
this.imageChanged = this.imageChanged.bind(this);
}
onDrop(files) {
this.addImages(files);
}
onDropRejected() {
alert('Invalid file type');
}
addImages(files) {
files.forEach(file => {
this.values.push({
title: '',
description: '',
url: file.preview,
file,
});
});
this.forceUpdate();
}
deleteImage(index) {
console.log('index to delete', index);
console.log('images pre-delete', cloneDeep(this.values)); // deep-copy because logging is async
this.values.splice(index, 1);
console.log('images post-delete', cloneDeep(this.values)); // deep-copy because logging is async
this.forceUpdate();
}
imageChanged(index, image) {
this.values[index] = image;
this.forceUpdate();
}
render() {
console.log('--------RENDER--------');
return (
<div className="image-list">
<div className="list-group">
{this.values.length === 0 ?
<div className="list-group-item">
No images
</div>
:
this.values.map((image, index) => {
console.log('rendering image', image);
return (
<ImageItem
key={index}
image={image}
onDelete={() => { this.deleteImage(index); }}
onChange={(item) => { this.imageChanged(index, item); }}
deletable={true}
/>
);
})
}
</div>
<Dropzone
multiple={true}
onDrop={this.onDrop}
onDropRejected={this.onDropRejected}
className="dropzone"
activeClassName="dropzone-accept"
rejectStyle={this.rejectStyle}
accept={'image/*'}
>
<span>Drop files here</span>
</Dropzone>
</div>
);
}
}
的ImagesList
組件可以與一些值(用於調試的緣故),它在渲染過程中使用的初始化。例如:
<ImagesList images={[
{ title: 'Image 1', description: 'Image 1 description', url: 'http://cssdeck.com/uploads/media/items/3/3yiC6Yq.jpg' },
{ title: 'Image 2', description: 'Image 2 description', url: 'http://cssdeck.com/uploads/media/items/4/40Ly3VB.jpg' },
{ title: 'Image 3', description: 'Image 3 description', url: 'http://cssdeck.com/uploads/media/items/0/00kih8g.jpg' },
]}/>
ImagesList
使得針對每個圖像的ImageItem
組件。這是該組件的樣子:
import React from 'react';
import { RIEInput, RIETextArea } from 'riek';
export class ImageItem extends React.Component {
constructor(props) {
super(props);
this.placeholder = {
title: 'Title',
description: 'Description',
};
this.value = this.props.image;
}
render() {
return (
<div className="list-group-item">
<div className="text-content">
<h4>
<RIEInput
className="description"
value={this.value.title.length <= 0 ?
this.placeholder.title : this.value.title}
change={(item) => {
this.value.title = item.value;
this.props.onChange(this.value);
}}
validate={(value) => value.length >= 1}
classEditing="form-control"
propName="value"
/>
</h4>
<span>
<RIETextArea
className="description"
value={this.value.description.length <= 0 ?
this.placeholder.description : this.value.description}
change={(item) => {
this.value.description = item.value;
this.props.onChange(this.value);
}}
validate={(value) => value.length >= 1}
classEditing="form-control"
propName="value"
rows="2"
/>
</span>
</div>
<img className="thumb img-responsive"
style={{width: '20%' }}
src={this.value.url}
alt="Image"
data-action="zoom"
/>
{this.props.deletable ?
<div className="delete-btn">
<span onClick={this.props.onDelete}>
×
</span>
</div>
:
undefined }
</div>
);
}
}
比方說,我有三個圖像,圖像A,B和C,我想刪除的圖像B.按刪除按鈕後,圖像C將會消失改爲GUI。
在ImagesList
的deleteImage()
函數中,我記錄了要刪除的索引,並記錄了刪除之前和之後的值。記錄的索引是正確的,在這種情況下,索引爲1
。在刪除之前,值是圖像A,B和C.在刪除之後,值是圖像A和C,它們應該是。
我決定在ImagesList
的render()
函數中做一些日誌記錄。不幸的是,這也會記錄正確的值A和C,但實際上會渲染A和B。
我也嘗試將React狀態用於此組件,而不是將它與forceUpdate()
一起存儲在局部變量中。
我試過的另一件事是使用Chrome的React開發工具插件。 Devtools也顯示正確的值,但GUI仍然沒有,如this screenshot所示。
我目前的想法是什麼嘗試,任何幫助將不勝感激! 使用我提供的片段,您應該能夠創建一個Meteor項目並重現此錯誤。
通常,您應該觸發對這些圖像原點上的圖像的更改。既然它們是作爲道具給予你的,那麼變化不應該發生在組件本身中。這通常是通過觸發一個動作來完成的,然後使用一個全局狀態管理器來更新映射到'props'的狀態。我很好奇你在哪裏看到組件更新以你在問題中演示的方式完成。 – MasterAM