我有个很奇怪的问题。我的意思是,对我来说,真的这不是某种“使用setState代替this.state”的问题。我正在开发旅行计划应用程序。我正在使用ContextAPI,它为整个应用程序提供登录信息和用户数据(记录的用户行程等)。 显示日常旅行计划的“计划”组件是上下文订户。 现在,我要删除旅行天数之一(“天”,也要预订上下文的是“日程表”列表中“日程表组件”所呈现的组件)。然后魔术发生了:
登录应用程序后立即执行此操作,则一切正常。但是,当我刷新页面并删除另一天时,上下文状态(如我所说的,将保存所有数据,包括日程安排列表中的天数)发生变化(通过开发人员工具进行了检查),但是Schedule组件并未重新呈现自身,因此删除的元素仍然可见。 但是正如我所说,状态会发生变化,并且在删除操作之前无需刷新页面就可以正常工作。同样,当我切换到另一个选项卡时(计划只是其中的一个选项卡,例如,我在导航栏上显示了Costs和Notes组件上有Costs and Notes选项卡),然后返回Schedule选项卡,它将重新渲染所有内容看起来不错,组件正在根据上下文状态显示信息。
代码的工作方式如下:删除(上下文函数)是通过在Day.js(上下文订阅者)中单击删除图标触发的,Day.js是由Schedule.js(也是上下文订阅者)呈现的。
在Context.js中
... context functions ...
//WRAPPER FOR DELETE FUNCTIONS
delete(url, deleteFunc) {
this.requestsApi.request(url, "DELETE", null)
.then(response => {
if(response.status===204) {
deleteFunc();
} else {
this.toggleRequestError(true);
}
})
.catch( err => {
console.log(err);
this.toggleRequestError(true);
});
}
deleteDay = (id, tripId) => {
let newTrip = this.state.userData.trips.find((trip => trip.id ===
tripId));
newTrip.days = newTrip.days.filter(day => day.id !== id)
this.updateTrip(newTrip);
}
updateTrip = (newTrip) => {
let trips = this.state.userData.trips;
this.setState(prevState => ({
userData : {
...prevState.userData,
trips: trips.map(trip => {
if(trip.id !== newTrip.id)
return trip;
else
return newTrip;
})
}
}
));
}
...
在Schedule.js中
... in render's return ...
<ul>
{this.trip.days.map((day,index) => {
return <DayWithContext
inOverview={false}
key={index}
number={index}
day={day}
tripId={this.trip.id}
/>
})}
</ul>
....
在Day.js中(删除图标)
...
<img
src={Delete}
alt="Delete icon"
className="mr-2"
style={this.icon}
onClick={() => {
this.props.context.delete(
`/days/${this.props.day.id}`,
() => this.props.context.deleteDay(this.props.day.id,
this.props.tripId)
);
}}
/>
...
任何人都知道发生了什么事,为什么页面刷新后删除后无法重新渲染Schedule?即使上下文状态发生变化?我目前唯一的想法是这是某种错误...
//更新 在Schedule组件的functionWillReceiveProps()函数中,我控制台记录props.context.trip [0] .day [0]-第一天。它不是一个对象,只是纯文本,因此它的评估结果不是“在控制台中单击时”。 在删除它之前,控制台会记录第一项。删除后,控制台会记录第二个项目(因此现在它是列表中的第一个项目),因此更改为Schedule的道具正在更改,但是没有触发渲染...到底发生了什么?
//更新2 我还注意到,当我从另一个组件切换到“计划”组件时,它运作良好(例如,我正在刷新/ costs端点上的页面,然后单击导航栏菜单上的“计划”选项卡,该页面会导致/ schedule)。但是,当我在/ schedule端点上刷新页面时,会出现此“错误”,并且组件没有重新呈现。
//从上下文渲染:
...
render() {
const {
isLoggedIn,
wasLoginChecked,
userData,
isLogoutSuccesfulActive,
isLogoutUnSuccesfulActive,
isDataErrorActive,
isRequestErrorActive,
isDataLoaded
} = this.state;
const context = {
isLoggedIn,
wasLoginChecked,
isLogoutSuccesfulActive,
isLogoutUnSuccesfulActive,
isDataErrorActive,
isRequestErrorActive,
userData,
isDataLoaded,
requestsApi : this.requestsApi,
toggleLogin : this.toggleLogin,
checkLogin: this.checkLogin,
setUserData: this.setUserData,
loadData: this.loadData,
addTrip: this.addTrip,
delete: this.delete,
deleteDay: this.deleteDay,
deleteActivity: this.deleteActivity,
deleteTrip: this.deleteTrip,
updateTrip: this.updateTrip,
uncheckLogin: this.uncheckLogin,
toggleLogoutSuccesful: this.toggleLogoutSuccesful,
toggleLogoutUnSuccesful: this.toggleLogoutUnSuccesful,
toggleRequestError: this.toggleRequestError,
toggleDataError: this.toggleDataError
};
return (
<Context.Provider value={context}>
{this.props.children}
</Context.Provider>
)
}
}
export const Consumer = Context.Consumer;
-------------上下文HOC:
export default function withContext(Component) {
return function ContextComponent(props) {
return (
<Context.Consumer>
{context => <Component {...props} context={context} />}
</Context.Consumer>
);
}
}
答案 0 :(得分:2)
您改变状态。 在这个地方,您无需使用setState即可更改状态下的对象:
newTrip.days = newTrip.days.filter(day => day.id !== id)
然后在您的map函数中,您总是返回相同的对象(已被更新)。
因此,要解决您的问题,您可以尝试更改deleteDay
方法:
deleteDay = (id, tripId) => {
const trip = this.state.userData.trips.find((trip => trip.id ===
tripId));
const newTrip = {...trip, days: trip.days.filter(day => day.id !== id)};
this.updateTrip(newTrip);
}
更新:
Schedule
组件中还有一个问题。
您需要动态获取当前行程,不要在构造函数中进行设置:
尝试一下:
constructor(props) {
super(props);
this.getTrip = this.getTrip.bind(this);
}
getTrip() {
return this.props.context.userData.trips.find(trip => {
return `${trip.id}`===this.props.match.params.id;
});
}
render() {
const trip = this.getTrip();
return (
...
<ul>
{trip.days.map((day,index) => {
return <DayWithContext
inOverview={false}
key={day.id}
number={index}
day={day}
tripId={trip.id}
/>
})}
</ul>
...
)
}