页面刷新后,即使状态发生更改,React也不会重新呈现组件

时间:2019-08-31 13:04:58

标签: javascript reactjs

我有个很奇怪的问题。我的意思是,对我来说,真的这不是某种“使用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>
    );
    }
}


1 个答案:

答案 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>
        ...
    )
}
相关问题