1
votes

I have a mobile app made in React Native, and I've just run into a best practice dilemma i've encountered many times while using Redux/Redux Saga. I would love if i could get someone else's thoughts on this.

For a new piece of functionality i'm implementing, i need to be able to tell how many times the app has been launched. This involves asynchronously retrieving how many times the app was previously launched from the device storage. If there's a new launch happening, i also need to add +1 to the number and store that in the device storage.

This is how i currently do it:

  1. Dispatch appLaunched() action when app launches.

  2. Redux Saga takes event.

  3. Inside Saga: Retrieve how many times app was previously launched (appLaunchCount) from device storage (wait for async to finish).

  4. Add +1 to previous appLaunchCount.

  5. Store new appLaunchCount in device storage (wait for async to finish).

  6. Dispatch put() with new appLaunchCount to reducer.

  7. Update state with new appLaunchCount inside reducer.

My problem with this method is step 6. Technically any part of my app could dispatch a new app launch count to my reducer, with any integer, and the reducer would update the state just the same even though it didn't come from the saga.

My question is this: How can i protect my Reducers/Sagas/Actions so that only my saga can dispatch the action with the current appLaunchCount ?

P.S The only solution i can think of is writing my saga and reducer in the same file, and use private actions that only the saga and reducer can access. I would really hate to have to keep all that code together though.

1

1 Answers

2
votes

Private actions aren't really a thing. The store is, by design, a global object. And since actions are just objects with a type property, anyone who can construct an action object of the right type can in principle dispatch an action and kick off your reducer.

What you could do is make the action have a type that makes it obvious that it's meant to be private. For example, maybe the action looks like:

{
  type: '__PRIVATE_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED__'
  // You could tone it down a bit from this :)
}

That of course doesn't make it actually private, but at least if someone wants to use it, it's impossible for them to not realize your intent.

If you wanted to make it more secure, perhaps you could use a symbol as the type, and therefore only anyone with access to the symbol could construct the right action. For example:

const appLaunchCount = Symbol('appLaunchCount');

// action would look like:
{
  type: appLaunchCount
}

But then the issue is making sure that symbol stays hidden, and can be accessed only by those who you want to access it. Similar to one of the things you mentioned, if you have the saga/reducer in the same file, then you could make sure that other files couldn't access this symbol; but once you start exporting it it becomes harder to control.