我有一个带有一个子组件的应用,当setState在父状态下更新bookInput时,我想重新渲染该子组件。我正在使用axios从Google的Book API请求信息。由于某种原因,即使状态正在更新,子级也不会重新渲染。如果可以的话请帮忙!谢谢!
import React, { Component } from 'react';
import axios from 'axios';
class App extends Component {
constructor(props) {
super(props);
this.state = {
bookInput: 'ender',
bookSubmitted: 'initial'
}
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.handleSubmitEmpty = this.handleSubmitEmpty.bind(this);
}
handleChange(e) {
this.setState({bookInput: e.target.value});
console.log(this.state.bookInput);
//this.setState({bookSubmitted: false});
}
handleSubmit(e) {
e.preventDefault();
//this.setState({bookSubmitted: true})
const name = this.state.bookInput;
this.setState({bookInput: name});
console.log(this.state);
this.setState({bookSubmitted: 'userSub'});
}
handleSubmitEmpty(e) {
alert('please enter an item to search for');
e.preventDefault();
}
render() {
return (
<div className="App">
<header className = "App-header">
<h1>Book Search App</h1>
</header>
<form className = "form-style" onSubmit = {this.state.bookInput ? this.handleSubmit: this.handleSubmitEmpty}>
<label>
<input type="text" className = "input-style"
value = {this.state.bookInput} onChange = {this.handleChange}>
</input>
</label>
<button type="submit">search books</button>
</form>
{/* <Book bookInput = {this.state.bookInput}/> */}
{/*this.state.bookSubmitted && <Book bookInput = {this.state.bookInput}/>*/}
{
(this.state.bookSubmitted === 'initial' || this.state.bookSubmitted === 'userSub') &&
<Book bookInput = {this.state.bookInput}/>
}
</div>
);
}
}
export default App;
class Book extends Component {
constructor(props) {
super(props);
this.state = {
//bookInput2: "ender",
bookTitles: [],
bookExample: '',
isLoading: false
}
this.bookClick = this.bookClick.bind(this);
}
bookClick(book) {
console.log(book);
console.log(book.volumeInfo.infoLink);
const bookURL = book.volumeInfo.infoLink;
window.open(bookURL);
}
componentDidMount() {
//this.setState({ isLoading: true });
this.setState({isLoading: true});
axios.get(`https://www.googleapis.com/books/v1/volumes?q=${this.props.bookInput}`)
.then((response) => {
const bookExample1 = response.data.items;
console.log(bookExample1);
this.setState({bookTitles: bookExample1, isLoading: false});
})
.catch((error) => {
console.error('ERROR!', error);
this.setState({isLoading: false});
});
}
render() {
return (
<div>
{ this.state.bookTitles ? (
<div>
<h2>book list</h2>
{<ul className = 'list-style'>
{this.state.isLoading &&
(<div>
loading book list
</div>)
}
{this.state.bookTitles.map(book => (
<li key={book.id}>
<span className = 'book-details book-title' onClick = {() => this.bookClick(book)}> {book.volumeInfo.title}</span>
<br/>
{book.volumeInfo.imageLinks &&
<img src = {book.volumeInfo.imageLinks.thumbnail}/>
}
{ book.volumeInfo.description &&
<span className = 'book-details'>{book.volumeInfo.description}</span>
}
<br/>
<span className = 'book-details'>Categories {book.volumeInfo.categories}</span>
</li>
))}
</ul>}
</div>) :
(<p>sorry, that search did not return anything</p>)}
</div>
);
}
}
答案 0 :(得分:1)
也许您正在寻找与此类似的东西? https://stackblitz.com/edit/react-snoqkt?file=index.js
以上代码可以进一步简化和组织,但可以为您提供一些思路。
代码中的主要更改。
将Api调用从componentDidMount生命周期事件更改为名为getInitialdata
的新方法,该方法在handleSubmit中调用。
getInitialdata(name){
axios.get(`https://www.googleapis.com/books/v1/volumes?q=${name}`)
.then((response) => {
const bookExample1 = response.data.items;
console.log(bookExample1);
this.setState({bookTitles: bookExample1, isLoading: false, bookSubmitted: 'userSub'});
})
.catch((error) => {
console.error('ERROR!', error);
this.setState({isLoading: false, bookSubmitted: 'userSub'});
});
}
更改了子组件的使用方式。
<Book bookTitles={this.state.bookTitles} isLoading={this.state.isLoading}/>
与您的代码有关的是您正在组件的didMount方法中进行API调用。仅在安装组件时才调用此生命周期事件。更新时不行。 当您在文本框中输入一些输入并单击“搜索书籍”时,componentDidMount事件不会触发。这就是第二次不进行API调用的原因。
有关https://reactjs.org/docs/react-component.html#componentdidmount上的生命周期事件的更多信息
答案 1 :(得分:0)
我已将您的代码插入到this sandbox中。就像您说的那样,您的父组件状态正在按需更新,但是问题在于子组件不会更改其状态。
状态更改将始终在React中触发重新渲染。唯一的问题是,您的子组件正在管理其自己的状态,不会直接更改。取而代之的是,它只是一次又一次地收到新的道具,而不对它们做任何事情。
如果您查看<Book />
组件的代码,则只能在componentDidMount
上修改其状态,这种状态只会发生一次。如果您想以编程方式对其进行更新,则可以执行以下两项操作之一。
componentDidUpdate
生命周期方法(docs)选择何时更改子状态(将触发重新渲染)