Guide
Using Mithril’s m.request for AJAX Calls and Automatic Redraw
Learn how to fetch JSON with m.request, let Mithril redraw automatically, and avoid common pitfalls.
Published by Tasadduq Burney
06 Oct 2025, 23:28 UTC
3 min16.6K views0

Quick answer
Fetch data with m.request inside a component’s oninit hook, store the result in a closure variable, and render it in the view. Mithril automatically redraws the component when the request settles, so you don’t need to call m.redraw yourself.
Worked example
const UserProfile = {
oninit: function(vnode) {
// Return the promise so Mithril knows when to redraw
return m.request({
method: 'GET',
url: '/api/user/123',
// optional: custom headers, serialization, etc.
}).then(function(result) {
// Store the parsed JSON in the vnode state
vnode.state.user = result;
}).catch(function(err) {
// Keep error state for the view
vnode.state.error = err;
});
},
view: function(vnode) {
if (vnode.state.error) {
return m('div.error', 'Failed to load user data');
}
if (!vnode.state.user) {
return m('div.loading', 'Loading…');
}
return m('div.user-card', [
m('h2', vnode.state.user.name),
m('p', 'Email: ' + vnode.state.user.email)
]);
}
};
m.mount(document.body, UserProfile);
How it works
m.requestreturns a native Promise that resolves with the parsed JSON body (or rejects with an error).- When Mithril sees a Promise returned from a lifecycle method (
oninit,oncreate,onupdate, etc.), it attaches a.thenhandler that triggers a redraw once the Promise settles. - The component’s view reads from
vnode.state, which is updated inside the.thenor.catchcallbacks, causing the UI to reflect the new data or error state automatically.
Limits and common mistakes
- Not returning the promise – If you omit
returnbeforem.request, Mithril won’t wait for the request and will render the view immediately, showing stale or empty data. - Ignoring error handling – A rejected promise leaves
vnode.state.userundefined; without a.catchthe component may stay in a loading state forever. - Mutating the response object – The parsed JSON is treated as immutable by Mithril’s redraw logic; changing properties directly can cause the view to not update because the reference stays the same.
- Overlapping requests – Rapid successive calls (e.g., on every keystroke) can cause flicker as each request triggers its own redraw. Track a loading flag or debounce calls to avoid this.
- No built‑in timeout or abort –
m.requestrelies on the underlyingfetch/XHR; you must implement timeout/abort logic yourself if needed. - File uploads – While you can pass a
FormDatabody, you must setserialize: x => xand appropriate headers; Mithril does not add multipart handling automatically.
Practical verification
- Open the page in a browser with Mithril 2.x loaded.
- Open DevTools → Network tab, reload if needed, and confirm a GET request to
/api/user/123appears. - Observe the UI: it should show “Loading…” then update with the user’s name and email once the response arrives.
- To test error handling, change the URL to a non‑existent endpoint (e.g.,
/api/user/999) and reload. The UI should display the error message, and the Network tab will show a 404 response.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.