DEV Community

Cover image for Improve React Navigation with xState v5
Georgi Todorov
Georgi Todorov

Posted on

Improve React Navigation with xState v5

TL;DR

If you just want to see the code, it is here. And this is the PR with the latest changes that are discussed in the post.

Introduction

This is a short follow up post that focuses on fine tuning the navigation integration. For full context refer to the previous part. The change was inspired by a discussion in the Stately discord channel, which I recommend joining.

Improvement

As I previously stated, I use xState as the backbone of the application. The end goal is to leave all the business logic and state orchestration to the machines and use the views/screens (in this case React Native ones) for the sole purpose of displaying the correct data in a fancy way. This not only makes the application framework agnostic, but also prepares it for proper model based testing.

That's why I had concerns with how the routing logic was tightly coupled with React via the useNavigator hook. When I started using React Navigation, I thought that utilising the navigation object through props is the only way to operate with the methods that it offers and a hook seemed as the obvious choice to synchronise machines and navigation. Slowly, the application evolved to rely solely on navigationRef, which left space for improvement.

Now we can move the navigation listener from the useNavigator hook into a fromCallback actor. Invoking the actor at the root level of the machine that is in charge of the navigation provides the same functionality without the need to go through the react-specific hooks.

actors: {
  homeMachine,
  listMachine,
  navigationSubscriber: fromCallback(({ sendBack }) => {
    const unsubscribe = navigationRef.addListener("state", (_event) => {
      const screenRoute = getCurrentRouteName();

      if (screenRoute) {
        sendBack({ type: "NAVIGATE", screen: screenRoute });
      }
    });

    return unsubscribe;
  }),
},
Enter fullscreen mode Exit fullscreen mode

As an extra step we can abstract the actor and reuse it for other machines in charge of navigation. In my case I export it from machines/shared/actors.ts

The last thing that's worth mentioning from this PR is a small change in the naming convention. Each machine that is tied with a <Stack.Navigator> and supports the NAVIGATE event will be renamed to machineName.navigator.ts. Since all machines share the same folder, and only few of them are serving this special role, I think we can give them a visual distinguisher in the folder tree.

Conclusion

Since we have the base set up, the upcoming posts will focus on Registration Wizard and Notification System.

Top comments (0)