为了给您一些背景信息,我附上了当前视图的屏幕截图:
卡片,表格,搜索和列表都是编辑页面上包含的所有独立组件。
当前,这种方式可以很好地将新项目添加到数据库中,并且React读取(Django)API以将项目显示为列表。
当您单击列表项时,卡片将通过在编辑页面上使用回调函数setState来显示文本,该页面会重新呈现所有组件,并将卡片对象作为prop类型传递给Card and Form。
在表单组件上,“提交”按钮使用状态来提交新数据。当我单击列表项时,我希望表单使用prop中传递的card对象填充字段。确实会发生这种情况,但是因为我要从prop设置状态,所以您无法编辑表单字段,因为它每次都会重新渲染prop对象。
我想我在这里或某些地方有一些隧道视野,因为我想不出另一种方法来做到这一点。任何帮助表示赞赏,并在此先感谢:)
编辑页面:
export default class Edit extends React.Component {
constructor(props) {
super(props);
this.state = {
cards: [],
loaded: false,
placeholder: "Loading Cards...",
card_to_load: null
};
this.handleCardClicked = this.handleCardClicked.bind(this);
}
async componentDidMount() {
try {
const res = await fetch('/api/cards/');
const cards = await res.json();
this.setState({cards: cards, loaded: true});
} catch (e) {
console.log(e);
}
}
handleCardClicked(id) {
const card = this.state.cards
.filter((c) => c.id === id);
this.setState({
card_to_load: card[0]
})
}
render() {
const {cards, loaded, placeholder, card_to_load} = this.state;
let card = null;
if (card_to_load !== null) {
card = card_to_load;
}
if (!loaded)
return (
<div>
<Card_Go_Back name={"Edit"}/>
<div>{placeholder}</div>
</div>
);
return (
<div className={styles.page_container}>
<Card_Go_Back name={"Edit"}/>
<div className={styles.preview_container}>
<div className={styles.card_container}>
<Card card={card}/>
</div>
<div className={styles.form_container}>
<Form card={card}/>
</div>
</div>
<List cards={cards} handleClick={this.handleCardClicked}/>
</div>
);
}
}
列表组件:
export default class List extends React.Component {
static propTypes = {
cards: PropTypes.array.isRequired
};
constructor(props) {
super(props);
this.state = {
filteredCards: this.props.cards
};
this.handleSearchFilter = this.handleSearchFilter.bind(this);
}
handleSearchFilter(filter) {
if (filter !== "")
this.setState({
filteredCards: this.props.cards
.filter(card =>
(
card.race_detail.title.toLowerCase().includes(filter.toLowerCase()) ||
card.card_text.toLowerCase().includes(filter.toLowerCase())
)
)
});
else
this.setState({filteredCards: this.props.cards});
}
render() {
return (
<div className={styles.races}>
<Search searchText={this.handleSearchFilter}/>
<div className={styles.races_list}>
<div className={`${styles.list_row} ${styles.list_header}`}>
<List_Row card={null}/>
</div>
{this.state.filteredCards.map(card => (
<div key={card.id} className={styles.list_row} onClick={() => this.props.handleClick(card.id)}>
<List_Row card={card}/>
</div>
))}
</div>
</div>
)
}
}
表单组件:
export default class Form extends React.Component {
constructor(props) {
super(props);
this.state = {
races: [],
loaded: false,
placeholder: "Loading Races...",
editing: false,
card_text: "",
card_description: "",
card_race: 0
};
this.handleReset = this.handleReset.bind(this);
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleReset() {
this.setState({
card_text: "",
card_description: "",
card_race: 0
});
}
handleChange(event) {
const target = event.target;
const value = target.value;
const name = target.name;
this.setState({
[name]: value
});
}
handleSubmit(event) {
event.preventDefault();
const {card_text, card_description, card_race} = this.state;
const input = {card_text, card_description, card_race};
const csrftoken = Cookies.get('csrftoken');
const data = {
method: "post",
body: JSON.stringify(input),
headers: new Headers({
"Content-Type": "application/json",
"X-CSRFToken": csrftoken
})
};
fetch("/api/cards/", data)
.then(response => console.log(response));
}
async componentDidMount() {
try {
const res = await fetch('/api/races/');
const races = await res.json();
this.setState({
races: races,
loaded: true
});
} catch (e) {
console.log(e);
}
}
render() {
let {races, loaded, placeholder, card_text, card_description, card_race} = this.state;
const card = this.props.card;
if (card !== null) {
card_text = card.card_text;
card_description = card.card_description;
}
if (!loaded)
return (
<div>
<Card_Go_Back name={"Edit"}/>
<div>{placeholder}</div>
</div>
);
return (
<div>
<form className={styles.form} onSubmit={this.handleSubmit}>
<div className={styles.reset}>
<label>Enter Card Text</label>
<label className={styles.btn_reset} onClick={this.handleReset}>
Reset Form
</label>
</div>
<div className={styles.card_input}>
<textarea value={card_text} placeholder={"Card Text..."}
name={"card_text"} maxLength={"100"} onChange={this.handleChange}>
{card_text}
</textarea>
</div>
<div className={styles.margin_top}>
<label>Enter Card Description</label>
</div>
<div className={styles.card_input}>
<textarea value={card_description} placeholder={"Card Description..."}
name={"card_description"} maxLength={"100"} onChange={this.handleChange}>
{card_description}
</textarea>
</div>
<div className={styles.margin_top}>
<label>Select Race Card Applies To</label>
</div>
<div className={styles.margin_top}>
<select className={styles.select} name={"card_race"} value={card_race}
onChange={this.handleChange}>
{races.map(race => (
<option key={race.id} value={race.id}>{race.title}</option>
))}
</select>
</div>
<div>
<input className={styles.btn_submit} type={"submit"} value={"Add New Card"}/>
</div>
</form>
</div>
)
}
}