我通过替换旧状态来更新道具的状态.在渲染中,数据被复制或使用新道具重置后从该状态多次渲染.它是在第一次渲染之后发生的.
这是应用程序的工作流程-当用户搜索位置时,获取操作首先发生.它会在用户位置周围显示“推荐位置”.它将数据作为“推荐位置”放入redux存储.有问题的组件从商店渲染数据[第一张图片],这很好.单击过滤器按钮时,这次它将获取用户位置和过滤器,并将数据放入redux商店中,例如restaurant = [],bars = []等.组件应从商店中获取新数据,并重新渲染.那就是我的问题所在.重新渲染时,似乎在复制数据[第二张图片].
这是有问题的组件-
import React,{ Component } from "react";
import PropTypes from "prop-types";
export default class Results extends Component {
state = {
places: []
};
getSnapshotBeforeUpdate(prevProps) {
const {places,restaurant,bar,coffee,bank,park} =
this.props.results;
if (prevProps.results.places !== places) {
this.setState({ places });
}
if (prevProps.results.restaurant !== restaurant) {
this.setState({ places: restaurant });
}
if (prevProps.results.bar !== bar) {
this.setState({ places: bar });
}
if (prevProps.results.coffee !== coffee) {
this.setState({ places: coffee });
}
if (prevProps.results.bank !== bank) {
this.setState({ places: bank });
}
if (prevProps.results.park !== park) {
this.setState({ places: park });
}
}
renderPlaces = () => this.state.places.map((place,i) => {
if (place.type || place.type === "Recommended Places") {
return place.items.map((item,i) => (
<tbody key={item.venue.id}>
<tr className="table-secondary">
<th scope="row">{item.venue.name}</th>
<td>
<h6>
{`${(item.venue.location.distance /
1609.344).toFixed(2)}`}{" "}
<cite>miles</cite>
</h6>
</td>
</tr>
</tbody>
));
}
return this.state.places.map((place,i) => (
<tbody key={place.id}>
<tr className="table-secondary">
<th scope="row">{place.name}</th>
<td>
<h6>
{`${(place.location.distance /
1609.344).toFixed(2)}`}{" "}
<cite>miles</cite>
</h6>
</td>
</tr>
</tbody>
));
})
render() {
return (
<React.Fragment>
{this.renderPlaces()}
</React.Fragment>
);
}
}
Results.propTypes = {
places: PropTypes.array,restaurant: PropTypes.array,coffee: PropTypes.array,bar: PropTypes.array,banks: PropTypes.array,parks: PropTypes.array
};
以下是父组件-
import React,{ Component } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import Results from "./Results";
class ResultList extends Component {
state = {
places: [],restaurant: [],bar: [],coffee: [],bank: [],park: []
};
getSnapshotBeforeUpdate(prevProps) {
const {
recommendedPlaces,restaurants,bars,banks,parks
} = this.props;
if (prevProps.recommendedPlaces !== recommendedPlaces) {
this.setState({ places: recommendedPlaces });
// returning a snapshot just in case I want to use..⬇
// componentDidUpdate in the future
return recommendedPlaces;
}
if (prevProps.restaurants !== restaurants) {
this.setState({ restaurant: restaurants });
// returning a snapshot just in case I want to use..⬇
// componentDidUpdate in the future
return restaurants;
}
if (prevProps.bars !== bars) {
this.setState({ bar: bars });
// returning a snapshot just in case I want to use..⬇
// componentDidUpdate in the future
return bars;
}
if (prevProps.coffee !== coffee) {
this.setState({ coffee });
// returning a snapshot just in case I want to use..⬇
// componentDidUpdate in the future
return coffee;
}
if (prevProps.banks !== banks) {
this.setState({ bank: banks });
// returning a snapshot just in case I want to use..⬇
// componentDidUpdate in the future
return banks;
}
if (prevProps.parks !== parks) {
this.setState({ park: parks });
// returning a snapshot just in case I want to use..⬇
// componentDidUpdate in the future
return parks;
}
return null;
}
render() {
const { address,filterBy } = this.props;
return (
<table className="primary table table-hover">
<thead>
<tr>
<th scope="col">
{filterBy === null ? "Places" : filterBy.toUpperCase()}
{
// eslint-disable-next-line
}{" "}
near
{
// eslint-disable-next-line
}{" "}
{address.toUpperCase()}
</th>
{/* this.showPlaces(recommendedPlaces,parks) */}
<th scope="col">Distance</th>
</tr>
</thead>
<Results results={this.state} />
</table>
);
}
}
ResultList.propTypes = {
address: PropTypes.string,filterBy: PropTypes.string,recommendedPlaces: PropTypes.array,restaurants: PropTypes.array,bars: PropTypes.array,parks: PropTypes.array
};
const mapStateToProps = state => ({
recommendedPlaces: state.places.recommendedPlaces,restaurants: state.places.restaurants,coffee: state.places.coffee,bars: state.places.bars,banks: state.places.banks,parks: state.places.parks
});
export default connect(mapStateToProps)(ResultList);
第一个是我搜索位置时的第一个渲染.完美渲染.它仅获取并呈现“推荐地点”.
其次是单击左侧的过滤器按钮后,当新道具进入状态重置状态后发生的渲染.它不会过滤位置数据.相反,它使用位置和过滤器获取并呈现新数据.
任何帮助深表感谢!
https://codesandbox.io/s/zw33318484
在自动完成搜索字段中搜索地址.它应使用“推荐位置”呈现页面的中间(ResultList.js和Result.js).然后选择“餐厅”过滤器.现在,它应该重新渲染商店中的餐馆.相反,它只是继续在渲染中添加餐厅.我认为它正在重新渲染,并不断在道具中连接餐厅阵列.它做了很多次,所以重新渲染.
renderPlaces = () => {
this.state.places.map((place,i) => {
if (place.type || place.type === "Recommended Places") {
// When first selecting a location from the autocomplete search,// you execute this code
return place.items.map((item,i) => (
<tbody key={item.venue.id}>
{/* stuff to render a place */}
</tbody>
));
}
// When you select a filter,you hit this condition instead.
return this.state.places.map((place,i) => (
<tbody key={place.id}>
{/* stuff to render a place */}
</tbody>
));
})
};
首次选择位置时,在this.state.places中只有一个条目,其place.type为“ Recommended Places”.那个地方有一系列驱动渲染的项目.当您选择一个过滤器(例如“餐馆”)时,地点有多个条目(在我看到的情况下为10个),而且它们都没有类型,因此符合第二个条件.第二个返回执行this.state.places.map调用,但是您仍然在外部this.state.places.map调用内,因此您对每个位置都遍历所有位置一次.因此,多余的副本与重新渲染的数量无关,而仅与位数有关.如果您删除第二个this.state.places.map,如下所示,它将正常工作(至少在这方面).
renderPlaces = () => {
this.state.places.map((place,i) => {
if (place.type || place.type === "Recommended Places") {
return place.items.map((item,i) => (
<tbody key={item.venue.id}>
{/* stuff to render a place */}
</tbody>
));
}
return (
<tbody key={place.id}>
{/* stuff to render a place */}
</tbody>
);
})
};