我有一个React应用,可以查询我在Spring Boot中构建的API。 React端应该查询数据库以找到许多Activity对象来填充一个Itinerary对象。我想跟踪活动的ID,因此该应用不会多次返回相同的ID。这是我的设置方式:
行程组件在其状态下具有一个名为“活动”的数组,该数组将保存ID。开始时为空。行程组件还具有一个名为UpdateActivities()
的函数,当添加活动时,该函数会使用新的ID更新状态。
UpdateActivities
作为回调传递给子组件Activity作为道具。状态中的活动数组将转换为字符串(因为我将在API调用中使用它),并且还作为道具传递给Activity
组件。
在Activity
组件中,回调函数作为道具进一步传递给ActivityDetails
组件,并且ID字符串也进一步传递给ActivityDetails
。 / p>
ActivityDetails
组件对Spring Boot应用程序进行实际的API调用,并使用回调函数更新父组件上的State。我试图将ID字符串保存为一个常量,以便在我的API调用中使用。我希望字符串在通话结束时显示,因此我的应用程序将知道跳过那些具有这些ID(当前已硬编码为1)的活动。
如果我将1替换为常量ID字符串,则API调用将不起作用,因为它显示为空。这是异步问题吗?有没有一种方法可以使React应用程序在父组件上的State更新之前不对ActivityDetails
进行API调用?
行程组成部分
class Itinerary extends Component {
constructor(props) {
super(props);
this.state = {
template: null,
activities: []
};
}
updateActivities = (id) => {
const activityList = [...this.state.activities, id];
this.setState({
activities: activityList
})
}
componentDidMount = () => {
const {duration, travelerType, pace} = this.props.userAnswers;
const transport = this.props.userAnswers.internalTravel.sort().join(', ');
const TEMPLATES_URL = `http://localhost:8080/templates/duration/${duration}/travelers/${travelerType}/pace/${pace}/transport/${transport}`;
axios.get(TEMPLATES_URL)
.then(response => {
this.setState({
template: response.data[0].content
});
})
.catch(function (error) {
console.log(error.message);
});
}
render() {
let cities;
if (this.state.template === null) {
cities = <div><h3>Loading...</h3></div>;
} else {
let data = this.state.template.split(", ");
cities = data.map((city, index) => {
return (
<section>
<City
key={index}
day={index + 1}
city={city}
/>
<Activity
key={`${city}${index}`}
day={index + 1}
lastDay={data.length}
city={city}
userAnswers={this.props.userAnswers}
updateActivityState={this.updateActivities}
activityList={this.state.activities.join(', ')}
/>
</section>
)
});
}
return (
<div>
<div className="row">
<div className="col s9">
<h3>{cities}</h3>
</div>
</div>
</div>
);
}
}
export default Itinerary;
活动组件
class Activity extends Component {
render() {
let city = this.props.city;
if(this.props.day === 1) {
return (
<ActivityDetails
userAnswers={this.props.userAnswers}
city={city}
timeOfDay="evening"
handleActivityList={this.props.updateActivityState}
activities={this.props.activityList}/>
);
} else if (this.props.day === this.props.lastDay) {
return (
<ActivityDetails
userAnswers={this.props.userAnswers}
city={city} timeOfDay="morning"
handleActivityList={this.props.updateActivityState}
activities={this.props.activityList} />
);
} else {
return(
<section>
<ActivityDetails
userAnswers={this.props.userAnswers}
city={city}
timeOfDay="morning"
handleActivityList={this.props.updateActivityState}
activities={this.props.activityList} />
<ActivityDetails
userAnswers={this.props.userAnswers}
city={city}
timeOfDay="afternoon"
handleActivityList={this.props.updateActivityState}
activities={this.props.activityList} />
<ActivityDetails
userAnswers={this.props.userAnswers}
city={city}
timeOfDay="evening"
handleActivityList={this.props.updateActivityState}
activities={this.props.activityList} />
</section>
);
}
}
}
export default Activity;
ActivityDetails组件
class ActivityDetails extends Component {
constructor(props) {
super(props);
this.state = {
activity: 'Loading...',
};
}
componentDidMount() {
const {travelParty, budget, pace, sites} = this.props.userAnswers;
const cityTravel = this.props.userAnswers.cityTravel.sort().join(', ');
const interests = this.props.userAnswers.interests.sort().join(', ');
const entertainment = this.props.userAnswers.entertainment.sort().join(', ');
const currentActivities = this.props.activities;
console.log(`currentActivities: ${currentActivities}`);
const city = this.props.city;
const timeOfDay = this.props.timeOfDay;
const ACTIVITY_URL = `http://localhost:8080/filter/${city}/${timeOfDay}/${travelParty}/${budget}/${pace}/${sites}/${cityTravel}/${interests}/${entertainment}/1`;
console.log(ACTIVITY_URL);
axios.get(ACTIVITY_URL)
.then(response => {
const newActivity = response.data.content;
const updatedActivityId = response.data.id;
this.props.handleActivityList(updatedActivityId);
this.setState({
activity: newActivity,
});
})
.catch(function(error) {
console.log(error.message);
});
}
render () {
return (
<div>{this.state.activity}</div>
);
}
}
export default ActivityDetails;
使用ComponentDidMount进行了修订:
class ActivityDetails extends Component {
constructor(props) {
super(props);
this.state = {
activity: 'Loading...',
};
}
getActivity() {
const {travelParty, budget, pace, sites} = this.props.userAnswers;
const cityTravel = this.props.userAnswers.cityTravel.sort().join(', ');
const interests = this.props.userAnswers.interests.sort().join(', ');
const entertainment = this.props.userAnswers.entertainment.sort().join(', ');
const city = this.props.city;
const timeOfDay = this.props.timeOfDay;
const currentActivities = this.props.activities;
console.log(`currentActivities: ${currentActivities}`);
const ACTIVITY_URL = `http://localhost:8080/filter/${city}/${timeOfDay}/${travelParty}/${budget}/${pace}/${sites}/${cityTravel}/${interests}/${entertainment}/${currentActivities}`;
console.log(ACTIVITY_URL);
axios.get(ACTIVITY_URL)
.then(response => {
const newActivity = response.data.content;
const updatedActivityId = response.data.id;
this.props.handleActivityList(updatedActivityId);
this.setState({activity: newActivity});
})
.catch(function(error) {
console.log(error.message);
});
}
componentDidMount() {
this.getActivity();
}
componentDidUpdate(prevProps) {
if(prevProps.activities !== this.props.activities) {
this.getActivity();
}
}
render () {
return (
<div>{this.state.activity}</div>
);
}
}
export default ActivityDetails;
答案 0 :(得分:0)
如果我将1替换为常量ID字符串,则API调用将不起作用,因为它显示为空。这是异步问题吗?
是的,是的。 Itinerary
的获取可能与ActivityDetails
的获取大致同时进行,因此state.activities
仍然有一个空数组(对它进行了突变后,请输入错误的空字符串然后传下来)。
有没有一种方法可以使React应用程序在父组件上的State更新之前不对ActivityDetails进行API调用?
是的,您可以使用其他生命周期方法来简化此过程。在您的情况下,您可能想要componentDidUpdate
。
您可以执行以下操作:
class ActivityDetails extends Component {
constructor(props) {
super(props);
this.state = {
activity: 'Loading...',
};
}
doMyGet(values) {
const ACTIVITY_URL = `http://localhost:8080/filter/${city}/${timeOfDay}/${travelParty}/${budget}/${pace}/${sites}/${cityTravel}/${interests}/${entertainment}/1`;
console.log(ACTIVITY_URL);
axios.get(ACTIVITY_URL)
.then(response => {
const newActivity = response.data.content;
const updatedActivityId = response.data.id;
this.props.handleActivityList(updatedActivityId);
this.setState({
activity: newActivity,
});
})
.catch(function(error) {
console.log(error.message);
});
}
componentDidMount() {
const {travelParty, budget, pace, sites} = this.props.userAnswers;
const cityTravel = this.props.userAnswers.cityTravel.sort().join(', ');
const interests = this.props.userAnswers.interests.sort().join(', ');
const entertainment = this.props.userAnswers.entertainment.sort().join(', ');
const currentActivities = this.props.activities;
console.log(`currentActivities: ${currentActivities}`);
const city = this.props.city;
const timeOfDay = this.props.timeOfDay;
this.doMyGet(currentActivities)
}
componentDidUpdate(prevProps) {
if (this.props.activities !== prevProps.activities) {
this.doMyGet(this.props.activities)
}
}
render () {
return (
<div>{this.state.activity}</div>
);
}
}
export default ActivityDetails;