現在、リストに画像を追加(そして後でアップロード)するために、MeteorにカスタムReactコンポーネントを作成しています。しかし、リストからイメージを削除しようとすると、最後の要素は常にGUIから削除されます。最初は、これは間違ったインデックスを削除のために使用した単純なケースだと思っていましたが、それ以上のものが判明しました。 ImagesList
コンポーネントがレンダリング中に使用する、(デバッグのために)いくつかの値で初期化することができレンダリングされたHTMLがReactコンポーネントと同期していません
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>
);
}
}
:
これは私のImageList
コンポーネントが現在のように見えるものです。例えば:
<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
の機能の中で、削除するインデックスをログに記録しておき、削除前後の値も記録します。記録されているインデックスは正しいです。この場合、インデックスは1
です。削除の前に値は画像A、B、Cです。削除後、値は画像AとCです。
ImagesList
のrender()
機能の中でいくつかのロギングを行うことにしました。残念ながら、これは正しい値AとCも記録しますが、実際にはAとBがレンダリングされます。
私はまた、forceUpdate()
と一緒にローカル変数に格納するのではなく、このコンポーネントのReact状態を使用しようとしました。
もう1つは、React Developer ToolsプラグインをChrome用に使用することです。 Devtoolsも正しい値を表示しますが、GUIはまだ表示されません(this screenshot)。
私は現在、何を試してみるかというアイデアがありません。 私が提供したスニペットを使って、Meteorプロジェクトを作成し、このバグを再現できるはずです。
一般に、それらの画像の原点にある画像に変更を加える必要があります。彼らは小道具としてあなたに与えられていたので、変更はコンポーネント自体で起こるべきではありません。これは通常アクションをトリガし、グローバル状態マネージャを使用して 'props'にマップされた状態を更新することによって行われます。私はあなたの質問でデモンストレーションする方法でコンポーネントのアップデートがどこで行われたのか、興味があります。 – MasterAM