【问题标题】:React/Redux Sort Function Not Updating StateReact/Redux 排序功能未更新状态
【发布时间】:2019-08-09 23:49:13
【问题描述】:

我有一个简单的 React/Redux 应用程序,它根据我的 Rails API 显示汽车列表。

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

虽然我的变量 orgArray 实际上在我 console.log 时按字母顺序排列,但我的 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 或在我最初的setState 中添加sortedCars: [] 会起作用。

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

更新:

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

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

// Async Actions

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

更新:

这也是 Reducer:

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;
  }
}

【问题讨论】:

  • 您可以在解析器中对数组进行排序吗?似乎没有必要将数组传递两次,一次未排序,一次排序。
  • 抱歉,我不知道你说的resolver是什么意思
  • 对不起,减速机
  • 等等,你的代码让我很困惑。在 sort 函数中,return 0; 之后的右括号是什么?
  • @James 是的,我会确保进入您的视图的数据已排序、清理并准备好使用。

标签: reactjs redux state


【解决方案1】:

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

另外,我认为这里的问题是您将 orgArray 传递给 this.props.sortCar(orgArray) 这是一个数组,而不是其中包含“cars”键和值的对象。

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

确保您的代码缩进。

【讨论】:

  • 好主意,我认为这将有助于解决方案,但我的 UI 没有更新。
  • @James 我更新了我的评论,检查了关于使用“cars”键传递数组而不是对象的部分,确保减速器正在做它应该做的事情。
  • 谢谢,感谢您的帮助!
  • 您正在调度SORT_CAR 类型的操作,但在reducer 中您期望SORT_CARS; 类型操作(您应该从名称中删除此分号),这也应该是您的问题应该像我之前建议的那样传递一个对象this.props.sortCar({cars: orgArray})
  • 你应该从预期的 reducer 操作中删除分号 case 'SORT_CARS' 而不是 case 'SORT_CARS;',你应该简单地调用 this.props.sortCar({cars: orgArray}) 而不是 this.props.sortCar(orgArray)
【解决方案2】:

排序只有一个参数(排序函数)。并且在您的 sortAlphabetically 方法中 setState (作为排序的第二个参数放置)没有被调用。 方法应该是这样的(我没测试过)

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);
    });
}

【讨论】:

  • 不幸的是,这也没有更新我的用户界面。状态保持平等
【解决方案3】:

得到了一个只使用本地状态而不是 Redux 存储的解决方案(不理想,但实现了这个功能)。

async 添加到我的componentDidMount 以及await 会等待更新数据,直到本地状态发生变化,然后这会反映在我的用户界面中。

感谢大家的帮助。

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);

【讨论】:

    【解决方案4】:

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

    请注意,默认情况下,sort() 方法按字母和升序将值排序为字符串。所以你不需要定义任何比较函数。

    1-u 可以定义另一个动作并让reducer 处理排序。问题就在这里,你必须确保你不会改变状态,所以使用 slice()

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

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

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

    【讨论】:

      猜你喜欢
      • 2019-05-30
      • 2021-01-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-30
      • 1970-01-01
      • 2022-01-20
      • 1970-01-01
      相关资源
      最近更新 更多