Let me put the Stack Overflow post that solved my problem here first.

I was doing essentially the same thing, but with activity editing. This is a function that I provided in the TripContext:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/** src/spa/contexts/TripContext.js **/

function updateOneActivity(activityPatch, activityId) {
const tripID = router.query.id;
axios
.patch(`${hostName}/api/trip/${tripID}/activities`, {
id: activityId,
...activityPatch,
})
.then(res => {
setActivities(
activities.map(activity =>
activityId === activity.id ? res.data.activity : activity,
),
);
})
.catch(err => {
setDialogError({
title: 'Activity Update Failed',
message: `Sorry, we failed to update the activity ${
activityPatch.name
} because: ${
err.response && err.response.data && err.response.data.message
? err.response.data.message
: 'An internal error happened'
}`,
});
setDialogErrorDisplay(true);
});
}

Note that I was trying to update activity by passing an array to setActivities.

This is how I used it in ActivityCard:

  • Component:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    /** src/spa/components/cards/ActivityCard.js, part of return statement **/
    <DateTimePicker
    value={activity.start}
    ampm={false}
    onChange={start =>
    handleEdit({ start }, updateOneActivity)
    }
    open={startChanging}
    onClose={() => setStartChanging(false)}
    TextFieldComponent={() => null}
    showTodayButton
    />
  • Handler:
    1
    2
    3
    4
    5
    6
    7
    8
    /** src/spa/components/cards/ActivityCard.js **/
    const handleEdit = (activityPatch, updateOneActivity) => {
    if (checkTimeValid(activityPatch)) {
    updateOneActivity(activityPatch, activityID);
    } else {
    setTimeErrorDisplay(true);
    }
    };

When I edit the activity, the database is updated but I dont get a page update.
If I log the activities in the console after the setActivity is called, I can see that the activities array remain the old value.

It is to be kept in mind that the setter defined with useState has the same behaviour as setState in class components. Have a look at the setState documentation.

setState() enqueues changes to the component state and tells React that this component and its children need to be re-rendered with the updated state.

Think of setState() as a request rather than an immediate command to update the component. For better perceived performance, React may delay it, and then update several components in a single pass. React does not guarantee that the state changes are applied immediately.

setState() does not always immediately update the component. It may batch or defer the update until later. This makes reading this.state right after calling setState() a potential pitfall. Instead, use componentDidUpdate or a setState callback (setState(updater, callback)), either of which are guaranteed to fire after the update has been applied. If you need to set the state based on the previous state, read about the updater argument below.

So my solution would be to pass setActivity with an updater function(state, props) => stateChange.

Here’s my updated code in the TripContext:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/** src/spa/contexts/TripContext.js **/

function updateOneActivity(activityPatch, activityId) {
const tripID = router.query.id;
axios
.patch(`${hostName}/api/trip/${tripID}/activities`, {
id: activityId,
...activityPatch,
})
.then(res => {
setActivities(
activities=> activities.map(activity =>
activityId === activity.id ? res.data.activity : activity,
),
);
})
.catch(err => {
setDialogError({
title: 'Activity Update Failed',
message: `Sorry, we failed to update the activity ${
activityPatch.name
} because: ${
err.response && err.response.data && err.response.data.message
? err.response.data.message
: 'An internal error happened'
}`,
});
setDialogErrorDisplay(true);
});
}

Works smooth like silk. Now when I update activities in ActivityCard or anywhere else, the Timeline of the trip will be updated.