我在从一个子组件的子组件向父组件以及从父子组件的另一组件发送信息时遇到问题。主要有3个组件(App.js)和两个子组件(MoviePoster.js和MovieDescription.js)。在App.js中,我们有一个名为ID的状态。我将带有setState的函数发送到MoviePoster,在onClick中使用它。函数设置id为我们的状态。 App.js将具有ID的道具发送到MovieDescription。在MovieDescription中,我使用API根据他的ID下载有关电影的信息。单击MoviePoster会更改ID并发送到MovieDescription,然后MovieDescription会呈现有关该电影的信息。我必须在MoviePoster上单击三下以呈现有关电影的新信息,但我不明白为什么在第三次单击后它仍然起作用,而在第一次单击后却不起作用。这是我的代码:
App.js
首先,我尝试将所有信息从API保存到几个状态。但是最后,它导致渲染元素的无限循环。因此,我将状态更改为全局变量。 其次,我试图像从代码中那样,从API下载到组件生命周期方法。
class App extends Component {
constructor(props) {
super(props)
this.updateId = this.updateId.bind(this)
}
state = {
response: '',
post: '',
responseToPost: '',
id: 438808
};
updateId = (id) => {
this.setState({id: id})
}
render() {
return (
<div className="App">
<MoviePoster updateId = {this.updateId} />
<MovieDescription id = {this.state.id} />
</div>
);
}
}
MoviePoster.js
class MoviePoster extends React.Component{
state = {
images: [],
title: []
}
handleImgClick = (id) => {
this.props.updateId(id);
}
componentDidMount(){
this.getMovie();
}
getMovie = ()=>{
axios.get('https://api.themoviedb.org/3/movie/upcoming?api_key=332654c71ccbb479020bcc047eaa43e8&language=en-US&page=1®ion=pl')
.then(res=>{
this.setState({
images: res.data.results.slice(0,4)
})
})
}
render(){
const { images } = this.state;
const posters = images.map( image => {
return(
<div onClick={() => this.handleImgClick(image.id)} className='poster-con'key={image.id}>
<div className='poster-s-con' >
<img className="poster responsive-img" src ={`http://image.tmdb.org/t/p/w300${image.poster_path}`} alt='img'/>
<h5 className='movie-title'>{image.title}</h5>
</div>
</div>
)
})
return(
<div className='movie-big-con white-text'>
<div className='movie-small-con'>
<div className='movie-con'>{posters}</div>
</div>
</div>
)}
};
export default MoviePoster;
MovieDescription.js
let data = {};
let data1 = {};
class MovieDescription extends React.Component {
componentWillMount() {
fetch(`https://api.themoviedb.org/3/movie/${this.props.id}?api_key=${api_key}&language=en-US`)
.then(response => response.json())
.then(json => {
data = json;
});
fetch(`https://api.themoviedb.org/3/movie/${this.props.id}/credits?api_key=${api_key}`)
.then(response => response.json())
.then(json => {
data1 = json;
});
}
componentWillUpdate() {
fetch(`https://api.themoviedb.org/3/movie/${this.props.id}?api_key=${api_key}&language=en-US`)
.then(response => response.json())
.then(json => {
data = json;
});
fetch(`https://api.themoviedb.org/3/movie/${this.props.id}/credits?api_key=${api_key}`)
.then(response => response.json())
.then(json => {
data1 = json;
});
}
render() {
return(
<div>{data.overview}</div>
<div>{data.runtime}</div>
);
}
}
我想在海报上单击一次,并重新渲染了MovieDescription组件,并从API下载了新内容。我不知道怎么了。
答案 0 :(得分:0)
将数据对象置于状态。当您从提取中获取json时,使用setState({})
更新数据。我认为那应该解决您的问题。理想情况下,您将在主要组件中完成所有这些操作,然后将数据作为道具传递给子组件。这样,您不必担心三个对象中的状态,只需一个。
答案 1 :(得分:0)
react中最好的部分是状态,即您没有在MovieDescription组件中使用它,因此将数据和data1变量移到组件状态下,这样无论何时执行setState,组件都将使用更新后的数据重新呈现。尽管使用了当前的MovieDescription组件代码,但您确实会进行调用,因为您要覆盖变量,因此不会将变量分配给变量,因此不会重新渲染组件。
也可以使用componentDidMount代替componentWillMount方法。如您所知,react v16版本不推荐使用componentWillMount。
这是更新的MovieDescription组件代码
class MovieDescription extends React.Component {
constructor(props){
super(props);
this.state = {
data:{},
data1: {}
}
}
componentDidMount() {
fetch(`https://api.themoviedb.org/3/movie/${this.props.id}?api_key=${api_key}&language=en-US`)
.then(response => response.json())
.then(json => {
this.setState({data : json});
});
fetch(`https://api.themoviedb.org/3/movie/${this.props.id}/credits?api_key=${api_key}`)
.then(response => response.json())
.then(json => {
this.setState({data1: json});
});
}
componentWillUpdate() {
fetch(`https://api.themoviedb.org/3/movie/${this.props.id}?api_key=${api_key}&language=en-US`)
.then(response => response.json())
.then(json => {
this.setState({data : json});
});
fetch(`https://api.themoviedb.org/3/movie/${this.props.id}/credits?api_key=${api_key}`)
.then(response => response.json())
.then(json => {
this.setState({data1 :json});
});
}
render() {
return(
<div>{data.overview}</div>
<div>{data.runtime}</div>
);
}
}