Action batching in MobX 6 when handling asynchronous retry loops
0 reputation · 04 Oct 2022, 19:30 UTC
0 reputation · 04 Oct 2022, 19:30 UTC
MobX 6 batches state changes made inside an action into a single notification, reducing unnecessary re-renders. When an asynchronous operation is retried, each attempt may trigger its own state update, potentially breaking the batching guarantee and causing duplicate writes.
Given the strict mode and action wrapper behavior, how can a retry loop be structured so that only the final successful state change triggers a reaction, without duplicating intermediate notifications? What patterns preserve action batching across asynchronous boundaries? Is there a way to defer or collapse multiple updates into a single action while preserving retry logic?
33775 reputation · 05 Oct 2022, 04:18 UTC
To prevent intermediate notifications and duplicate writes during a retry loop, you must decouple the retry logic from the state update logic. In MobX 6, action batching only occurs within an action wrapper or runInAction block. Because await breaks the synchronous execution, any state changes following an await are executed outside the original action batch.
The most effective way to preserve action batching is to perform the retry logic using local variables and wrap the final state assignment in a single runInAction call once the loop completes. This ensures that reactions only fire once with the final successful state.
import { makeAutoObservable, runInAction,er } from "mobx";
class DataStore {
data = null;
loading = false;
error = null;
constructor() {
makeAutoObservable(this);
}
async fetchWithRetry(attempts = 3) {
this.loading = true;
let lastError = null;
let result = null;
for (let i = 0; i < attempts; i++) {
try {
result = await apiCall();
break; // Success exit loop
} catch (err) {
lastError = err;
if (i < attempts - 1) await new Promise(r => setTimeout(r, 1000));
}
}
// Batch all final updates into a single notification
runInAction(() => {
this.data = result;
this.error = lastError;
this.loading = false;
});
}
}
this.status inside the for loop loop unless you specifically want a reaction for every failure.runInAction at the very end of the function to commit the result. This satisfies strict mode while collapsing multiple potential updates into one notification.This approach assumes you are using MobX 6 with strict mode enabled (default). To verify that batching is working, use the spy own or autorun to confirm the reaction only executes once after the loop finishes, regardless of how many retries occurred.
Diagnostic Question: Does the UI need to show real-time retry progress (e.g., "Attempt 2 failed..."), or is only the final result mattering? If real-time progress is required, you must wrap intermediate updates in runInAction, which will intentionally trigger multiple notifications.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.