我有一个简单的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;
}
}
答案 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存储的解决方案(虽然不理想,但可以实现此功能)。
将async
与componentDidMount
一起添加到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()
})
}