React / Redux排序功能未更新状态

时间:2019-03-19 12:34:11

标签: reactjs redux state

我有一个简单的React / Redux应用,该应用基于我的Rails API显示汽车列表。

我正在尝试添加一种排序功能,以按汽车名称的字母顺序排列。

当我在console.log上输入变量orgArray时实际上是按字母顺序排列的,但是我的Redux开发工具在单击排序按钮后会说states are equal-因此我的UI不会更新。

这是我的代码:

import React, { Component } from 'react';
import { connect } from 'react-redux';
import CarCard from '../components/CarCard';
import CarForm from './CarForm';
import './Cars.css';
import { getCars } from '../actions/cars';
import { sortCar } from '../actions/cars';

Component.defaultProps = {
  cars: { cars: [] }
}

class Cars extends Component {
  constructor(props) {
    super(props)
      this.state = {
        cars: [],
        sortedCars: []
      };
  }

sortAlphabetically = () => {
    console.log("sort button clicked")
    const newArray = [].concat(this.props.cars.cars)
    const orgArray = newArray.sort(function (a,b) {
      var nameA = a.name.toUpperCase();
      var nameB = b.name.toUpperCase();
          if (nameA < nameB) {
            return -1;
          } else if (nameA > nameB) {
            return 1;
          } 
            return 0;
          }, () => this.setState({ cars: orgArray }))  
            console.log(orgArray)
            this.props.sortCar(orgArray);
          }

    componentDidMount() {
        this.props.getCars()
        this.setState({cars: this.props.cars})
        }


    render() {
        return (
        <div className="CarsContainer">
    <h3>Cars Container</h3> 
        <button onClick={this.sortAlphabetically}>Sort</button>
        {this.props.cars.cars && this.props.cars.cars.map(car => <CarCard key={car.id} car={car} />)}  
        {/* {this.state.cars.cars && this.state.cars.cars.map(car => <CarCard key={car.id} car={car} />)}           */}
        <CarForm />
    </div>
    );
  }
}

 const mapStateToProps = (state) => {
   return ({
    cars: state.cars
  })
}

const mapDispatchToProps = (dispatch) => {
  return {
    sortCar: (cars) => dispatch(sortCar(cars)),
    getCars: (cars) => dispatch(getCars(cars))
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(Cars);

我猜想mapStateToProps或在我最初的sortedCars: []中添加setState都是可以的。

从本质上讲,我的道具正在更新,但是我也需要更新状态-尽管我不确定自己缺少什么。

已更新:

这是我的动作创建者和异步动作(如果有帮助的话):

const sortCars = cars => {
 return {
    type: 'SORT_CARS',
    cars
  }
}

// Async Actions

export const sortCar = (cars) => {
  console.log(cars, 'cars object');
  return dispatch => {
    dispatch(sortCars(cars))
   }
}

更新:

这也是减速器:

export default (state = {cars: []}, action) => {
switch(action.type) {
    case 'GET_CARS_SUCCESS':

    return Object.assign({}, state, {cars: action.payload})

    case 'CREATE_CAR_SUCCESS':

    return Object.assign({}, state, {cars: action.payload})

    case 'REMOVE_CAR;':
    return state.filter(car => car.id !== action.id)

    case 'SORT_CARS;':
    return Object.assign({}, state, { cars: action.payload})

    default:
        return state;
  }
}

4 个答案:

答案 0 :(得分:1)

首先,我认为您实际上不需要任何状态,您只需更新商店并展示道具上的汽车即可。

此外,我认为这里的问题是,您将orgArray传递给this.props.sortCar(orgArray),它是一个数组,而不是内部带有“ cars”键和值的对象。

除了该setState调用外,还被声明为匿名函数,而不是在排序后实际执行。

请确保您的代码缩进。

答案 1 :(得分:0)

排序仅具有一个参数(排序功能)。并且在您的sortAlphabetically方法中,不会调用setState(作为sort的第二个参数放置)。 该方法应该是这样的(我没有测试过)

sortAlphabetically = () => {
    console.log("sort button clicked")
    const newArray = this.props.cars.cars.slice();
    const orgArray = newArray.sort(function (a, b) {
        var nameA = a.name.toUpperCase();
        var nameB = b.name.toUpperCase();
        if (nameA < nameB) {
            return -1;
        } else if (nameA > nameB) {
            return 1;
        }
        return 0;
    });
    this.setState({ cars: orgArray }, () => {
        console.log(orgArray);
        this.props.sortCar(orgArray);
    });
}

答案 2 :(得分:0)

有一个只使用本地状态而不是Redux存储的解决方案(虽然不理想,但可以实现此功能)。

asynccomponentDidMount一起添加到await中,等待数据更新,直到本地状态更改,然后反映在我的UI中。

感谢大家的帮助。

import React, { Component } from 'react';
import { connect } from 'react-redux';
import CarCard from '../components/CarCard';
import CarForm from './CarForm';
import './Cars.css';
import { getCars } from '../actions/cars';
import { sortCar } from '../actions/cars';

Component.defaultProps = {
  cars: { cars: [] }
}

class Cars extends Component {
  constructor(props) {
  super(props)
  this.state = {
    cars: [],
    sortedCars: []
  };
}

sortAlphabetically = () => {
    console.log("sort button clicked")
    const newArray = [].concat(this.props.cars.cars)
    const orgArray = newArray.sort(function (a,b) {
          var nameA = a.name.toUpperCase();
          var nameB = b.name.toUpperCase();
              if (nameA < nameB) {
                return -1;
              } else if (nameA > nameB) {
                return 1;
              } 
               return 0;
              })  
            console.log(orgArray)
            this.props.sortCar(orgArray);
            this.setState({ cars: {cars: orgArray} })
}

async componentDidMount() {
    await this.props.getCars()
    this.setState({cars: this.props.cars})
}

render() {
    return (
    <div className="CarsContainer">
        <h3>Cars Container</h3> 
        <button onClick={this.sortAlphabetically}>Sort</button>
        {this.state.cars.cars && this.state.cars.cars.map(car => <CarCard key={car.id} car={car} />)}          
        <CarForm />
    </div>
    );
  }
}

 const mapStateToProps = (state) => {
  return ({
    cars: state.cars
  })
}

const mapDispatchToProps = (dispatch) => {
  return {
    sortCar: (cars) => dispatch(sortCar(cars)),
    getCars: (cars) => dispatch(getCars(cars))
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(Cars);

答案 3 :(得分:0)

您不应使用setState()。 setState()不会立即使this.state发生突变,但会创建一个挂起的状态转换。调用此方法后,this.state可能会返回现有值。所以这里是如何处理排序的。

请注意,默认情况下,sort()方法将这些值按字母和升序排序为字符串。因此您无需定义任何比较函数。

1-u可以定义另一个动作,并由减速器处理排序。事情在这里,你必须确保你不改变状态,所以使用slice()

case 'SORT_CARS':
  return state.slice().sort()

2-您可以定义一个函数并将状态作为参数传递并返回排序后的状态。

const mapStateToProps = (state) => {
  return ({
    cars: state.cars.sort()
  })
}