很长一段时间后,我开始重新学习React。我几乎有一个“列表”,用于存储公司面试过程。这是由2个React组件构建的。是汇总每个作业的列表。
当您转到“删除行”时,react寄存器将删除正确的“行”(并且通过使用调试简单的情况发生),但是不会成功更新内部组件。
我花了很多时间研究这个问题,并且添加了一个简单的组件“ Welcome”。这对我有帮助,因为我可以使用它来验证是否删除了正确的元素,只是内部的“作业”组件未正确更新。
https://codepen.io/anon/pen/XwaWPj
class Jobs extends React.Component {
constructor(props) {
super(props);
this.state = {
name: "",
jobs: props.data.items
//jobs: [{ id: "" }]
};
}
handleAddJob = () => {
this.setState({
jobs: this.state.jobs.concat([{ "company":"", "position": "", "next_steps": []}])
});
console.log(this.state);
};
handleRemoveJob = key => () => {
//var index = this.state.jobs.indexOf(items)
console.log(this.state.jobs.filter((item, j) => item.key !== key) )
this.setState({
//shareholders: this.state.shareholders.filter((s, sidx) => idx !== sidx)
//next_steps: this.state.next_steps.splice(idx, 1)
jobs: this.state.jobs.filter((item, j) => item.key !== key)
});
};
//<JobRow
// company={items.company}
// position={items.position}
// next_steps={items.next_steps}/>
render() {
return (
<div>
<h4>Jobs Applied</h4>
{this.state.jobs.map((items =>
<div>
<Welcome name={items.company} />
<JobRow
company={items.company}
position={items.position}
next_steps={items.next_steps}/>
<button
type="button"
onClick={this.handleRemoveJob(items.key)} //.bind(this)
className="small">
remove row
</button>
</div>
))
}
<button
type="button"
onClick={this.handleAddJob}
className="small">
Add New Job
</button>
</div>
)
};
}
// ===========
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
// ===========
//https://stackoverflow.com/questions/50147840/how-to-format-and-display-json-data-using-array-map-in-reactjs
class JobRow extends React.Component {
constructor(props) {
super(props);
this.state = {
company: props.company,
position: props.position,
next_steps: props.next_steps,
};
}
handleNameChange = evt => {
this.setState({ name: evt.target.value });
};
handleAddField = () => {
this.setState({
//shareholders: this.state.shareholders.concat([{ name: "" }])
next_steps: this.state.next_steps.concat("")
});
};
handleRemoveField = idx => () => {
this.setState({
//shareholders: this.state.shareholders.filter((s, sidx) => idx !== sidx)
//next_steps: this.state.next_steps.splice(idx, 1)
next_steps: this.state.next_steps.filter((s, sidx) => idx !== sidx)
});
};
changeTextCompany(event){
this.setState(
//"{this.state.textValue : event.target.value}"
{company: event.target.value}
);
}
render() {
return (
<div>
<div class="flex-container">
<div class="inner_flex">
<span>
<input type="text" class="form-control" placeholder="Company" value={this.state.company} id="comapny_input" onChange={this.changeTextCompany}/>
</span>
<span>
<input type="text" class="form-control" placeholder="Position" value={this.state.position} oninput="selectJobType()" id="position_input"/>
</span>
<span>
<select id="position_type">
<option value="fulltime">Fulltime</option>
<option value="intern">Co-Op/Internship</option>
</select>
</span>
</div>
{this.state.next_steps.map((step, idx) => (
<span>
<button
type="button"
onClick={this.handleRemoveField(idx)}
className="small"
>
-
</button>
<input placeholder="Next State" value={step} />
</span>
))}
<button
type="button"
onClick={this.handleAddField}
className="small">
Next Stage
</button>
</div>
</div>
);
}
}
我希望删除的正确行反映在文本框中。
非常感谢您的反馈。
答案 0 :(得分:0)
您需要为元素数组中的每个项目赋予一个键(您应该得到关于此的控制台警告)。键应该是唯一的标识符,而不是数组索引。用您的密码笔代替
{this.state.jobs.map((items =>
<div>
尝试
{this.state.jobs.map((items =>
<div key={items.key}>
然后正确删除您选择的行。并研究为什么将数组索引用作键(或者为什么不对组件数组完全使用键)在React中引起问题。
答案 1 :(得分:0)
使用getDerivedStateFromProps更新JobsRow中的状态。
.flex-container {
display: flex;
background-color: #f1f1f1;
}
.flex-container > div {
background-color: #B6E3DC;
margin: 0px;
padding: 5px;
}
.flex-container > div > span {
display: inline-block;
padding: 2.5px;
}
input {display: block !important; padding: 0 !important; margin: 0 !important; border: 0 !important; width: 100% !important; border-radius: 0 !important; line-height: 1 !important;}
td {margin: 0 !important; padding: 0 !important;}
input {display: block !important; padding: 0 !important; margin: 0 !important; border: 0 !important; width: 100% !important; border-radius: 0 !important; line-height: 1 !important;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.0/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.21.1/babel.min.js"></script>
<div id="root"></div>
<script type="text/babel">
var json = {"items":[
{"key":132, "company":"Google", "position": "SE Intern", "next_steps": ["Coding", "phone"]
},
{"key":133, "company":"FaceBook", "position": "DS Intern", "next_steps": ["Onsite", "Offer"]
},
{"key":134, "company":"twitter", "position": "architectre", "next_steps": ["coffeechat", "denail"]
},
{"key":135, "company":"oracle", "position": "sleeping", "next_steps": []
}
]}
class Jobs extends React.Component {
constructor(props) {
super(props);
this.state = {
name: '',
jobs: this.props.data.items
//jobs: [{ id: "" }]
};
}
handleAddJob = () => {
this.setState({
jobs: this.state.jobs.concat([
{ company: '', position: '', next_steps: [] }
])
});
console.log(this.state);
};
handleRemoveJob = key => () => {
//var index = this.state.jobs.indexOf(items)
//console.log(this.state.jobs.filter((item, j) => item.key !== key));
this.setState({
//shareholders: this.state.shareholders.filter((s, sidx) => idx !== sidx)
//next_steps: this.state.next_steps.splice(idx, 1)
jobs: this.state.jobs.filter((item, j) => item.key !== key)
});
};
//<JobRow
// company={items.company}
// position={items.position}
// next_steps={items.next_steps}/>
render() {
return (
<div>
<h4>Jobs Applied</h4>
{this.state.jobs.map(items => (
<div>
<Welcome name={items.company} />
<JobRow
company={items.company}
position={items.position}
next_steps={items.next_steps}
/>
<button
type="button"
onClick={this.handleRemoveJob(items.key)} //.bind(this)
className="small"
>
remove row
</button>
</div>
))}
<button type="button" onClick={this.handleAddJob} className="small">
Add New Job
</button>
</div>
);
}
}
// ===========
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
// ===========
//https://stackoverflow.com/questions/50147840/how-to-format-and-display-json-data-using-array-map-in-reactjs
class JobRow extends React.Component {
constructor(props) {
super(props);
this.state = {
company: props.company,
position: props.position,
next_steps: props.next_steps
};
}
static getDerivedStateFromProps(props, state) {
// compare props with state data
// if they are not equal return props
// or return null
// more info here https://reactjs.org/docs/react-component.html#static-getderivedstatefromprops
return props;
}
handleNameChange = evt => {
this.setState({ name: evt.target.value });
};
handleAddField = () => {
this.setState({
//shareholders: this.state.shareholders.concat([{ name: "" }])
next_steps: this.state.next_steps.concat('')
});
};
handleRemoveField = idx => () => {
this.setState({
//shareholders: this.state.shareholders.filter((s, sidx) => idx !== sidx)
//next_steps: this.state.next_steps.splice(idx, 1)
next_steps: this.state.next_steps.filter((s, sidx) => idx !== sidx)
});
};
changeTextCompany(event) {
this.setState(
//"{this.state.textValue : event.target.value}"
{ company: event.target.value }
);
}
render() {
return (
<div>
<div class="flex-container">
<div class="inner_flex">
<span>
<input
type="text"
class="form-control"
placeholder="Company"
value={this.state.company}
id="comapny_input"
onChange={this.changeTextCompany}
/>
</span>
<span>
<input
type="text"
class="form-control"
placeholder="Position"
value={this.state.position}
oninput="selectJobType()"
id="position_input"
/>
</span>
<span>
<select id="position_type">
<option value="fulltime">Fulltime</option>
<option value="intern">Co-Op/Internship</option>
</select>
</span>
</div>
{this.state.next_steps.map((step, idx) => (
<span>
<button
type="button"
onClick={this.handleRemoveField(idx)}
className="small"
>
-
</button>
<input placeholder="Next State" value={step} />
</span>
))}
<button type="button" onClick={this.handleAddField} className="small">
Next Stage
</button>
</div>
</div>
);
}
}
ReactDOM.render(<Jobs data={json}/>, document.getElementById('root'));
</script>
另一种选择是直接在JobsRow中访问道具,而不是将其保存为状态。
<span>
<input
...
value={this.props.company}
...
/>
</span>
<span>
<input
...
value={this.props.position}
...
/>
</span>