所以我从API中获取电影信息。在我的页面中,我在下拉列表中有三个选项可按字母,用户评分和受欢迎程度进行排序。
问题在于,当我选择一个选项时,它会按照之前的选项进行排序。例如,当我选择按用户分数排序时,它按字母顺序排序,这是下拉列表中的选项。然后,如果我继续选择选项,它最终会变得随机并与其中任何一个进行排序。
不确定为什么会这样。我猜它与我如何设置状态有关。
这是我的代码:
import React, {Component} from "react";
import {connect} from "react-redux";
import {crimeGenre} from "./redux";
class CrimeGenre extends Component {
constructor(){
super();
this.state = {
value: "alphabetically"
}
}
componentDidMount(){
this.props.crimeGenre();
}
sortFilms = (event) => {
this.setState({
value: event.target.value
})
if(this.state.value === "alphabetically"){
return this.props.select && this.props.select.sort((a, b) => {
return a.title < b.title ? -1 : 1;
});
}else if(this.state.value === "score"){
return this.props.select && this.props.select.sort((a, b) => {
return a.vote_average > b.vote_average ? -1 : 1;
});
}else if(this.state.value === "popularity"){
return this.props.select && this.props.select.sort((a, b) => {
return a.popularity > b.popularity? -1 : 1;
});
}
}
render(){
const mappedSelected = this.props.select && this.props.select.map((film, i) => {
return (
<div key={i}>
<h1>{film.title}</h1>
<img src={`http://image.tmdb.org/t/p/w185${film.poster_path}`}/>
<p>Avg. User Score: {film.vote_average}</p>
<p>Popularity Index: {film.popularity.toFixed(0)}</p>
</div>
)
})
return(
<div>
<form>
<label>
Sort By:
<select value={this.state.value} onChange={this.sortFilms}>
<option id="alphabetically" value="alphabetically">Alphabetically</option>
<option id="score" value="score">User Score</option>
<option id="popularity" value="popularity">Popularity</option>
</select>
</label>
</form>
{mappedSelected}
</div>
)
}
}
export default connect(state=> state, {crimeGenre})(CrimeGenre);
答案 0 :(得分:0)
React的setState()
不会立即反映状态值的更新,但会创建挂起状态转换。调用setState()
后访问状态可能会返回现有值。
无法保证对setState
的调用进行同步操作,并且可以对调用进行批处理以获得性能提升。
查看官方ReactJS Docs,以便更好地解释这一点。
要确保您的sortFilms
函数使用新状态,请将其作为setState()
的回调传递给您:
sortFilms = (event) => {
this.setState({value: event.target.value}, function () {
if(this.state.value === "alphabetically"){
return this.props.select && this.props.select.sort((a, b) => {
return a.title < b.title ? -1 : 1;
});
}else if(this.state.value === "score"){
return this.props.select && this.props.select.sort((a, b) => {
return a.vote_average > b.vote_average ? -1 : 1;
});
}else if(this.state.value === "popularity"){
return this.props.select && this.props.select.sort((a, b) => {
return a.popularity > b.popularity? -1 : 1;
});
}
});
}
答案 1 :(得分:0)
您需要更改一些事项
首先使用你的选择道具设置你的初始状态,如
constructor(props){
super(props);
this.state = {
value: "alphabetically",
select: props.select
}
}
您希望这样做是因为您希望在选择更改(或其顺序更改)时重新呈现,这就是它属于组件状态的原因。
现在进入sortFilm函数,在对值进行排序后设置状态:
sortFilms = event => {
const sorter = event.target.value;
const films = this.state.select;
if (sorter === "alphabetically") {
films.sort((a, b) => {
return a.title < b.title ? -1 : 1;
});
} else if (sorter === "score") {
films.sort((a, b) => {
return a.vote_average > b.vote_average ? -1 : 1;
});
} else if (sorter === "popularity") {
films.sort((a, b) => {
return a.popularity > b.popularity ? -1 : 1;
});
}
//Now we set the state to cause the re-render
this.setState({ value: sorter, select: films });
};
最后消耗我们的状态,每当我们提交文件时,我们将使用我们的状态而不是像
这样的道具const mappedSelected = this.state.select && this.state.select.map((film, i) => {
return (
<div key={i}>
<h1>{film.title}</h1>
<img src={`http://image.tmdb.org/t/p/w185${film.poster_path}`}/>
<p>Avg. User Score: {film.vote_average}</p>
<p>Popularity Index: {film.popularity.toFixed(0)}</p>
</div>
)
})
现在您的代码出现了问题:
您正在设置导致渲染的状态并且是异步的,因此当您通过对其进行排序来更改道具时,组件无法知道道具已更改。因此,当导致下一次重新渲染时,组件会更新并开始使用新的道具,当您开始快速更改过滤器时,即使在设置状态之前多次更改道具,这也会开始随机行为。
来自AndrewL的代码由于类似的原因而失败,它设置状态并导致重新渲染,然后更改道具,组件没有新的道具在那里更新。