我通过替换旧状态来更新道具的状态。在渲染中,数据被复制或使用新道具重置后从该状态多次渲染。它是在第一次渲染之后发生的。
这是应用程序的工作流程-用户搜索位置时,首先发生获取操作。它会在用户位置周围显示“推荐位置”。它将数据作为“推荐位置”放入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,
coffee,
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, restaurants, bars, 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,
coffee: PropTypes.array,
bars: PropTypes.array,
banks: 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)。然后选择“餐厅”过滤器。现在,它应该重新渲染商店中的餐馆。相反,它只是继续在渲染中添加餐厅。我认为它正在重新渲染,并不断在道具中连接餐厅阵列。它需要花费很多时间才能重新渲染。
答案 0 :(得分:2)
问题出在您的renderPlaces
函数中。下面是一个简化版本,使查看结构变得容易。
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
。该place
具有一个驱动渲染的items
数组。当您选择一个过滤器(例如“餐馆”)时,places
有多个条目(在我看到的情况下为10),并且它们都没有type
,因此符合第二个条件。第二个返回将进行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>
);
})
};