Skip to content

Instantly share code, notes, and snippets.

@luke-rmaki
Created July 10, 2021 08:23
Show Gist options
  • Select an option

  • Save luke-rmaki/5824414ddf367f78bde1c5a662d8bb2f to your computer and use it in GitHub Desktop.

Select an option

Save luke-rmaki/5824414ddf367f78bde1c5a662d8bb2f to your computer and use it in GitHub Desktop.
FSM React Nav
// STATE MACHINE
const states = {
MOBILE_DISPLAY: `MOBILE_DISPLAY`,
BUTTON_HIDDEN: `BUTTON_HIDDEN`,
BUTTON_DISPLAY: `BUTTON_DISPLAY`,
DESKTOP_DISPLAY: `DESKTOP_DISPLAY`,
DESKTOP_HIDDEN: `DEKSTOP_HIDDEN`,
};
const events = {
SCROLL_DOWN: `SCROLL_DOWN`,
SCROLL_UP: `SCROLL_UP`,
BUTTON_CLICK: `BUTTON_CLICK`,
CLOSE_CLICK: `CLOSE_CLICK`,
TO_DESKTOP_WIDTH: `TO_DESKTOP_WIDTH`,
TO_MOBILE_WIDTH: `TO_MOBILE_WIDTH`,
};
const machine = {
initial: states.BUTTON_DISPLAY,
states: {
[states.MOBILE_DISPLAY]: {
on: {
[events.CLOSE_CLICK]: states.BUTTON_DISPLAY,
[events.TO_DESKTOP_WIDTH]: states.DESKTOP_DISPLAY,
},
},
[states.BUTTON_HIDDEN]: {
on: {
[events.SCROLL_UP]: states.BUTTON_DISPLAY,
[events.TO_DESKTOP_WIDTH]: states.DESKTOP_DISPLAY,
},
},
[states.BUTTON_DISPLAY]: {
on: {
[events.SCROLL_DOWN]: states.BUTTON_HIDDEN,
[events.BUTTON_CLICK]: states.MOBILE_DISPLAY,
[events.TO_DESKTOP_WIDTH]: states.DESKTOP_DISPLAY,
},
},
[states.DESKTOP_DISPLAY]: {
on: {
[events.SCROLL_DOWN]: states.DESKTOP_HIDDEN,
[events.TO_MOBILE_WIDTH]: states.MOBILE_DISPLAY,
},
},
[states.DESKTOP_HIDDEN]: {
on: {
[events.SCROLL_UP]: states.DESKTOP_DISPLAY,
[events.TO_MOBILE_WIDTH]: states.BUTTON_DISPLAY,
},
},
},
};
const stateTransition = (state: string, event: string) =>
machine.states[state].on[event] || state;
const [state, send] = useReducer(stateTransition, machine.initial);
// HANDLE EVENTS
// Scroll
// use ref to keep last value on re-render
const previousScrollPosition: MutableRefObject<number> = useRef(0);
useEffect(() => {
function handleScroll() {
const currentScroll = window.scrollY;
if (previousScrollPosition.current < currentScroll) {
send(events.SCROLL_DOWN);
} else {
send(events.SCROLL_UP);
}
previousScrollPosition.current = currentScroll;
}
// use passive option to optmise scrolling
window.addEventListener(`scroll`, handleScroll, { passive: true });
// Window Size
function handleResize(entries: any) {
const { width }: { width: number } = entries[0].contentRect;
if (width > 1000) {
send(events.TO_DESKTOP_WIDTH);
} else {
send(events.TO_MOBILE_WIDTH);
}
}
const resizeObserver = new ResizeObserver(handleResize);
const body = document.querySelector(`body`);
if (body) {
resizeObserver.observe(body);
}
// remove event listener on unmount
return () => {
window.removeEventListener(`scroll`, handleScroll);
if (body) {
resizeObserver.unobserve(body);
}
};
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment