React navigation is a really powerful library. But you often don't need that much.
Building your library for this case teaches you a lot about React Context API and how simple the navigation in a SPA happens.
Integration
export function App() {
return (
<NavProvider>
<Router></Router>
</NavProvider>
);
}
Defining our routes
export function Router() {
const navContext = useContext(NavContext);
switch (navContext.current.path) {
case 'cockpit':
return (
<Cockpit/>
);
default:
return <header>
<Navbar/>
</header>
}
}
Under the hood?
export function NavProvider({children, entryPath}) {
const [current, setCurrent] = useState({path: entryPath, params: {}});
const [history, setHistory] = useState([current]);
const loadFromHash = () => {
const pathFromHash = window.location.hash.split('#')[1]
setCurrent({path: pathFromHash});
setHistory([{path: pathFromHash}])
}
useEffect(() => {
window.addEventListener("hashchange", e => loadFromHash());
loadFromHash();
}, []);
const updateCurrent = ({path, params}) => {
window.location.hash = `${path}`;
setCurrent({path, params});
}
const push = (path, params) => {
setHistory(prev => [...prev, {path, params}]);
updateCurrent({path, params});
}
const back = () => {
history.pop();
const previousItem = history[history.length - 1];
setHistory(history);
updateCurrent(previousItem);
}
return <NavContext.Provider value={{ setCurrent: updateCurrent, current, push, back }}>
{children}
</NavContext.Provider>;
}
Does your component need access to params?
No problem!
export function Cockpit() {
const {current} = useContext(NavContext);
const navParams = current.params;
return <p>{JSON.stringify(navParams)}</p>
}
Do you want to navigate back and forth?
No problem! You can just use the push
and back
API from our NavContext
.
Conclusion
In most cases, you should go with react-navigation. It will save you a lot of time and just don't reinvent the wheel. However, within a side project that has just too few features to matter, you might learn a lot about routing from implementing it yourself.