89Implement a basic client-side router using the History API
mediumAbout 45 minutesCodingroutinghistory-apispa
Problem
Implement a small single-page-app router.
1. History adapters with the same interface, { location, push(path), replace(path), back(), listen(callback) → unlisten }, where location is { pathname, search }:
createBrowserHistory()useshistory.pushState,history.replaceStateand thepopstateevent. Note thatpushStatedoes not firepopstate, sopushandreplacemust notify listeners themselves.createMemoryHistory(initialPath = "/")keeps entries in an array. It is used for tests and server rendering. (The editor's sandboxed preview blockspushState, so the tests use this one.)
2. createRouter(routes, history), where routes is [{ path: "/users/:id", name }] and "*" matches anything:
router.match(pathname)returns{ name, params }for the first matching route;:segmentsbecome params (URL-decoded). Trailing slashes are ignored.router.current()returns the match for the current location plusquery(an object from the search string).router.navigate(path, { replace = false })updates the history.router.subscribe(callback)callscallback(router.current())after every navigation, including back/forward.router.handleLinkClick(event)intercepts clicks on<a href="/…">and navigates instead of reloading. It must ignore modified clicks (Ctrl, ⌘, Shift, Alt), non-left buttons, links withtargetordownload, external links (http…,//…,mailto:), and events alreadydefaultPrevented.
Try it yourself
Write your solution, run it, then submit to check it against the tests.
App.jsxReact + DOM
Step-by-step
The router only talks to { location, push, replace, back, listen }. Swapping the browser implementation for a memory one makes the router testable and usable on the server.
Unlock the full solution
What's inside
- Step-by-step
- Approach
- Solution
- Complexity
- Edge cases
- Follow-up questions
- Tests
Includes 2 code listings, 5 edge cases, 4 follow-up questions.
One-time payment by UPI, card or net banking. Launch price.