我知道这是最常见的反应问题之一:“为什么状态不能正确更新我的组件?”而且我已经搜索了很多东西并尝试了很多东西,但似乎无法解决这个问题。
这个问题最常见的答案是我在某个地方改变状态,但我无法发现它。
我正在尝试使用标签创建一个表单,根据我发现的这篇文章,我也可以动态添加表单字段:https://goshakkk.name/array-form-inputs/
一切正常,但是当我删除动态添加的表单时,表单数组的值不会根据状态更新。
我的代码如下:
import React, { Component } from 'react';
import EditorFooter from '../../editor/moduleEditor/Footer';
import EditorHeader from '../../editor/moduleEditor/Header';
class Tab extends Component {
render() {
const currentTabNumber = this.props.currentTabNumber;
const cssClass = currentTabNumber === this.props.number ? 'active' : '';
return (
<button className={`tab ${cssClass}`} onClick={(e) => this.props.switchTab(this.props.number)}>{this.props.name}</button>
)
};
};
class CourseForm extends Component {
render() {
const index = this.props.index;
return (
<div className="inner-form">
<h3>Kurs {index}</h3>
<button className="removeForm" onClick={this.props.handleRemoveCourse(index)}>Remove form</button>
<h4>Kursens namn</h4>
<input type="text" name="name" defaultValue={this.props.course.name} onChange={this.props.handleInputChange(index)} />
<h4>Årtal</h4>
<p className="helper-text">Exempel: 2002-2003</p>
<input type="text" name="years" defaultValue={this.props.course.years} onChange={this.props.handleInputChange(index)} />
</div>
)
};
};
class Editable extends Component {
constructor(props) {
super(props);
this.state = {
showTab: 1,
};
}
switchTab = (tabNr) => {
this.setState({ showTab: tabNr });
}
render() {
const courses = this.props.courses;
const coursesList = courses.map((course, index) =>
<CourseForm key={index} index={index} course={course} handleInputChange={this.props.handleCourseChange} handleRemoveCourse={this.props.handleRemoveCourse} />
);
return (
<div id={`${this.props.moduleItem.ModuleId}_Editor`} className="form notransition">
<EditorHeader templateName="Simple test form" />
<section className="form-inner">
<div className="tabs">
<Tab switchTab={this.switchTab} currentTabNumber={this.state.showTab} number={1} name="Information" />
<Tab switchTab={this.switchTab} currentTabNumber={this.state.showTab} number={5} name="Kurser" />
</div>
{this.state.showTab === 1 ?
<div className="tab-block">
<h4>Bild</h4>
<p className="helper-text">Tänk på att cv-bilden ska vara av bra kvalitet. Låt gärna en fotograf komma och fota hela projektgruppen.</p>
<input type="file" name="image" defaultValue={this.props.image} onChange={this.props.handleInputChange} />
<h4>Slogan</h4>
<p className="helper-text">Om du skulle skriva en kort reklamslogan om dig själv, vad skulle det vara?</p>
<textarea name="slogan" defaultValue={this.props.slogan} onChange={this.props.handleInputChange}></textarea>
</div>
:
null
}
{this.state.showTab === 5 ?
<div className="tab-block">
{coursesList}
<button className="addForm" onClick={this.props.handleAddCourse}>Add form</button>
</div>
:
null
}
</section>
<EditorFooter {...this.props} submitForm={this.props.saveForm} />
</div>
);
}
};
class Readable extends Component {
render() {
const props = this.props;
return (
<section className="module align-top notransition">
</section>
);
}
};
class Template extends Component {
render() {
const props = this.props;
return (
<section className="module align-top">
</section>
);
}
};
class SimpleTestForm extends Component {
constructor(props) {
super(props);
this.state = {
slogan: "",
image: "",
courses: [{ name: '', years: '' }],
};
}
onAddCourseForm = (event) => {
this.setState({
courses: this.state.educations.concat([{ name: '', years: '' }])
});
}
handleCourseChange = (index) => (e) => {
const newCourses = this.state.courses.map((course, newIndex) => {
if (index !== newIndex) return course;
const target = e.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
return { ...course, [name]: value };
});
this.setState({ courses: newCourses });
}
handleRemoveCourse = (index) => (e) => {
this.setState({
courses: this.state.courses.filter((courses, newIndex) => index !== newIndex)
});
//this.setState( this.state );
}
handleAddCourse = () => {
this.setState({
courses: this.state.courses.concat([{ name: '', years: '' }])
});
}
saveForm = (e) => {
console.log(this.state);
}
handleInputChange = (e) => {
const target = e.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
}
render() {
const inEditMode = this.props.mode === 'edit';
const inTemplateMode = this.props.mode === 'template';
const inReadMode = this.props.mode === 'read';
return (
<div>
{inEditMode ?
<Editable {...this.props}
handleInputChange={this.handleInputChange}
onChangeEditor={this.onChangeEditor}
saveForm={this.saveForm}
handleCourseChange={this.handleCourseChange}
handleAddCourse={this.handleAddCourse}
handleRemoveCourse={this.handleRemoveCourse}
courses={this.state.courses}
slogan={this.state.slogan}
image={this.state.image}
/>
:
null
}
{inReadMode ?
<Readable {...this.props}
/>
:
null
}
{inTemplateMode ?
<Template {...this.props}
/>
:
null
}
</div>
);
}
};
module.exports = SimpleTestForm;
我知道它有点长,我试图把它煮沸。
我的麻烦是,如果我在“Kruser”选项卡下添加三个表单,然后填写它们,然后删除中间的表单,删除正确的表单(我可以看到,如果我记录状态),但它的数据来自它下面的表格。在我切换标签并返回Kurser标签之前,它会显示正确的数据。
答案 0 :(得分:2)
您不应将数组索引用作键。这是我可以识别的可能导致您的问题的一件事。
如果我的数据没有唯一标识符,我经常使用shortid生成一个。首先yarn add shortid
或npm i --save shortid
import { generate } from 'shortid';
// Update, it seems to work better if the unique id is generated on the object itself
...
handleAddCourse = () => {
this.setState({
courses: this.state.courses.concat([{ name: '', years: '', itemKey: generate() }])
});
}
...
const coursesList = courses.map((course, index) =>
<CourseForm
key={course.itemKey}
index={index}
course={course}
handleInputChange={this.props.handleCourseChange}
handleRemoveCourse={this.props.handleRemoveCourse} />
);
希望这可以解决你的问题,如果不是,至少你听说过这种反模式。 Here您可以通过示例找到介绍此主题的文章。
另一个提示是,有一种更简洁,更清晰的方式来编写这些星球。
有效,但难以阅读
{inReadMode ?
<Readable {...this.props}
/>
:
null
}
更清洁
{inReadMode &&
<Readable {...this.props} />
}
请参阅react docs。