为什么内容按错误的选项排序?

时间:2018-06-02 21:06:13

标签: javascript reactjs sorting redux

所以我从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);

2 个答案:

答案 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的代码由于类似的原因而失败,它设置状态并导致重新渲染,然后更改道具,组件没有新的道具在那里更新。