在 React 中渲染子项后设置父级状态
Setting parent state after child rendered in React
我正在从事图书馆项目。用户可以将书籍添加到图书馆。
所以,我创建了添加一本书的表单。该表单包含来自名称、作者、出版商、页面、ISBN 和信息字段。我为作者和出版商创建了下拉组件,因此用户可以从该组件中进行选择:
import AuthorsService from './AuthorsService'
const authorsService = new AuthorsService();
class AuthorsDropDown extends Component {
constructor(props) {
super(props);
this.state = {
authors: [],
};
}
componentDidMount() {
var self = this;
authorsService.getAuthors().then(function (result) {
self.setState({ authors: result});
});
}
render() {
return (
<div className="form-group col-sm-4">
<label>Author:</label>
<select className="form-control" onChange={(ev) => this.props.onChange(ev.target.value)}>
{this.state.authors.map( a =>
<option key={a.id} value={a.id}>{a.first_name + ' '+a.last_name }
</option>)
}
</select>
</div>
);
}
}
export default AuthorsDropDown;
我已将父组件中的 author.id 和 publisher.id 字段的初始值指定为 null,但是,这些字段仅在下拉列表更改后(即触发 onChange 后)才获得它们的值。我不知道如何在渲染时为它们设置值(即初始化状态)。这是父组件:
import React, { Component } from "react";
import BookService from "./BooksService";
import AuthorsDropDown from "./AuthorsDropDown";
import PublishersDropDown from "./PublishersDropDown";
const bookService = new BookService();
class BookCreateUpdate extends Component {
constructor(props) {
super(props);
this.state = {
author:{id:null},
publisher:{id:null}
}
this.handleSubmit = this.handleSubmit.bind(this);
this.onChangeAuthor = this.onChangeAuthor.bind(this);
this.onChangePublisher = this.onChangePublisher.bind(this);
}
onChangeAuthor(new_author_id){
this.setState({author:{id:new_author_id}});
}
onChangePublisher(new_publisher_id){
this.setState({publisher:{id:new_publisher_id}});
}
handleCreate() {
alert(this.state.author.id);
bookService
.createBook({
name: this.refs.name.value,
author: this.state.author,
publisher: this.state.publisher,
page: this.refs.pages.value,
inventor_number: this.refs.inventor_number.value,
description: this.refs.description.value
})
.then(result => {
alert("The book is added!");
})
.catch(() => {
alert("Error!!");
});
}
handleUpdate(pk) {
bookService
.updateBook({
pk: pk,
name: this.refs.name.value,
author: this.refs.author,
publisher: this.refs.publisher,
pages: this.refs.pages.value,
description: this.refs.description.value
})
.then(result => {
console.log(result);
alert("Success");
})
.catch(() => {
alert("Error.");
});
}
handleSubmit(event) {
const {
match: { params }
} = this.props;
if (params && params.pk) {
this.handleUpdate(params.pk);
} else {
this.handleCreate();
}
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<div className="row">
<div className="form-group col-sm-8">
<label>Name:</label>
<input
className="form-control"
type="text"
ref="name"/>
</div>
</div>
<div className="row">
<AuthorsDropDown onChange={this.onChangeAuthor}/>
<PublishersDropDown onChange={this.onChangePublisher}/>
</div>
<div className="row">
<div className="form-group col-sm-4">
<label>Pages:</label>
<input
className="form-control"
type="number"
ref="pages"/>
</div>
<div className="form-group col-sm-4">
<label>ISBN:</label>
<input
className="form-control"
type="text"
ref="inventor_number"/>
</div>
</div>
<div className="row">
<div className="form-group col-sm-4">
<label>Info:</label>
<textarea
className="form-control"
ref="description"/>
</div>
</div>
<input className="btn btn-primary" type="submit" value="ok"/>
</form>
);
}
}
export default BookCreateUpdate;
我认为你应该考虑用不同的方法来解决这个问题。如果我理解你的要求,这个组件既可以创建也可以更新书籍。在这种情况下,<BookCreateUpdate/>
组件应该接收一个 属性,它是目标书。对于创建,它应该是一个空对象。对于更新,它应该是要更新的对象。
我认为提到的问题与编辑时有关。我想这些书一直存在于某个地方。如果一本书是在编辑模式下传递的,那么初始值应该从父级 (<BookCreateUpdate/>
) 向下传递给子组件 (input, AuthorsDropDown, PublishersDropDown)。
class BookCreateUpdate extends Component {
constructor(props) {
super(props);
this.state(this.props.book)
}
onInputChange = propName => (e) => {
this.setState({[propName]: e.target.value })
}
...
handleCreate() {
const bookDraft = this.state;
bookService
.createBook(bookDraft)
.then(result => {
alert("The book is added!");
})
.catch(() => {
alert("Error!!");
});
}
...
render(){
const bookDraft = this.state;
return (
...
<div className="row">
<div className="form-group col-sm-8">
<label>Name:</label>
<input
className="form-control"
type="text"
value = {bookDraft.name}
onChange={this.onInputChange('name')}
/>
</div>
</div>
<AuthorsDropDown onChange={this.onChangeAuthor} authorId = {bookDraft.authorId}/>
<PublishersDropDown onChange={this.onChangePublisher} publisherId = {bookDraft.publisherId}/>
....
)
}
}
BookCreateUpdate.propsTypes = {
book: PropTypes.object
}
BookCreateUpdate.defaultProp = {
book: {authorId: null, publisherId: null}
}
在这种情况下最好不要使用 refs。将值传递给输入并传递 onChange 事件的回调更清晰。
我正在从事图书馆项目。用户可以将书籍添加到图书馆。 所以,我创建了添加一本书的表单。该表单包含来自名称、作者、出版商、页面、ISBN 和信息字段。我为作者和出版商创建了下拉组件,因此用户可以从该组件中进行选择:
import AuthorsService from './AuthorsService'
const authorsService = new AuthorsService();
class AuthorsDropDown extends Component {
constructor(props) {
super(props);
this.state = {
authors: [],
};
}
componentDidMount() {
var self = this;
authorsService.getAuthors().then(function (result) {
self.setState({ authors: result});
});
}
render() {
return (
<div className="form-group col-sm-4">
<label>Author:</label>
<select className="form-control" onChange={(ev) => this.props.onChange(ev.target.value)}>
{this.state.authors.map( a =>
<option key={a.id} value={a.id}>{a.first_name + ' '+a.last_name }
</option>)
}
</select>
</div>
);
}
}
export default AuthorsDropDown;
我已将父组件中的 author.id 和 publisher.id 字段的初始值指定为 null,但是,这些字段仅在下拉列表更改后(即触发 onChange 后)才获得它们的值。我不知道如何在渲染时为它们设置值(即初始化状态)。这是父组件:
import React, { Component } from "react";
import BookService from "./BooksService";
import AuthorsDropDown from "./AuthorsDropDown";
import PublishersDropDown from "./PublishersDropDown";
const bookService = new BookService();
class BookCreateUpdate extends Component {
constructor(props) {
super(props);
this.state = {
author:{id:null},
publisher:{id:null}
}
this.handleSubmit = this.handleSubmit.bind(this);
this.onChangeAuthor = this.onChangeAuthor.bind(this);
this.onChangePublisher = this.onChangePublisher.bind(this);
}
onChangeAuthor(new_author_id){
this.setState({author:{id:new_author_id}});
}
onChangePublisher(new_publisher_id){
this.setState({publisher:{id:new_publisher_id}});
}
handleCreate() {
alert(this.state.author.id);
bookService
.createBook({
name: this.refs.name.value,
author: this.state.author,
publisher: this.state.publisher,
page: this.refs.pages.value,
inventor_number: this.refs.inventor_number.value,
description: this.refs.description.value
})
.then(result => {
alert("The book is added!");
})
.catch(() => {
alert("Error!!");
});
}
handleUpdate(pk) {
bookService
.updateBook({
pk: pk,
name: this.refs.name.value,
author: this.refs.author,
publisher: this.refs.publisher,
pages: this.refs.pages.value,
description: this.refs.description.value
})
.then(result => {
console.log(result);
alert("Success");
})
.catch(() => {
alert("Error.");
});
}
handleSubmit(event) {
const {
match: { params }
} = this.props;
if (params && params.pk) {
this.handleUpdate(params.pk);
} else {
this.handleCreate();
}
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<div className="row">
<div className="form-group col-sm-8">
<label>Name:</label>
<input
className="form-control"
type="text"
ref="name"/>
</div>
</div>
<div className="row">
<AuthorsDropDown onChange={this.onChangeAuthor}/>
<PublishersDropDown onChange={this.onChangePublisher}/>
</div>
<div className="row">
<div className="form-group col-sm-4">
<label>Pages:</label>
<input
className="form-control"
type="number"
ref="pages"/>
</div>
<div className="form-group col-sm-4">
<label>ISBN:</label>
<input
className="form-control"
type="text"
ref="inventor_number"/>
</div>
</div>
<div className="row">
<div className="form-group col-sm-4">
<label>Info:</label>
<textarea
className="form-control"
ref="description"/>
</div>
</div>
<input className="btn btn-primary" type="submit" value="ok"/>
</form>
);
}
}
export default BookCreateUpdate;
我认为你应该考虑用不同的方法来解决这个问题。如果我理解你的要求,这个组件既可以创建也可以更新书籍。在这种情况下,<BookCreateUpdate/>
组件应该接收一个 属性,它是目标书。对于创建,它应该是一个空对象。对于更新,它应该是要更新的对象。
我认为提到的问题与编辑时有关。我想这些书一直存在于某个地方。如果一本书是在编辑模式下传递的,那么初始值应该从父级 (<BookCreateUpdate/>
) 向下传递给子组件 (input, AuthorsDropDown, PublishersDropDown)。
class BookCreateUpdate extends Component {
constructor(props) {
super(props);
this.state(this.props.book)
}
onInputChange = propName => (e) => {
this.setState({[propName]: e.target.value })
}
...
handleCreate() {
const bookDraft = this.state;
bookService
.createBook(bookDraft)
.then(result => {
alert("The book is added!");
})
.catch(() => {
alert("Error!!");
});
}
...
render(){
const bookDraft = this.state;
return (
...
<div className="row">
<div className="form-group col-sm-8">
<label>Name:</label>
<input
className="form-control"
type="text"
value = {bookDraft.name}
onChange={this.onInputChange('name')}
/>
</div>
</div>
<AuthorsDropDown onChange={this.onChangeAuthor} authorId = {bookDraft.authorId}/>
<PublishersDropDown onChange={this.onChangePublisher} publisherId = {bookDraft.publisherId}/>
....
)
}
}
BookCreateUpdate.propsTypes = {
book: PropTypes.object
}
BookCreateUpdate.defaultProp = {
book: {authorId: null, publisherId: null}
}
在这种情况下最好不要使用 refs。将值传递给输入并传递 onChange 事件的回调更清晰。