4

I'm trying to learn react with redux, I've read in the main documentation of redux, we should store actions types into one js files and then export all constants and use them into type, for example it's simple mode:

export function itemsAction(items) {
    return {
        type: 'ITEMS',
        data: items
    }
}

But apparently I should do in this format:

import { types } from './Types';

export function itemsAction(items) {
    return {
        type: types.ITEMS,
        data: items
    }
}

But what's the main benefit of this trick? actions are fixed and never changes, why I should set the action types from variables and import all types ?

Thanks

Alex
  • 335
  • 5
  • 17
  • 3
    If you decide to change types.ITEMS in the future, you only have to change it in one spot. If you want to change 'ITEMS' in the future, you have to do it in every single file, where you used it. – willy1994 Jun 03 '19 at 06:43
  • @willy1994 thanks for that comment, you've convinced me! – TKoL Dec 12 '19 at 11:07
  • Let's go one step further: const FOO_BAR_COOKIE = 'foo_bar_cookie_key_name'; - why are these constants usually ALL_CAPS? – Devin Rhode May 19 '20 at 21:38
  • If a company is familiar with a certain browser cookie, fooBarId, and throughout a codebase, you only see FOO_BAR_ID - it creates a level of indirection/complection where now I have to check "what the heck is `FOO_BAR_ID`?" If it's name matches the actual value, maybe it helps a little?... unless you are familiar with an established convention that ALL_CAPS things are always string constants... – Devin Rhode May 19 '20 at 21:41

3 Answers3

7

Because it's good to know you're using an object property rather than a raw string, since raw strings are prone to typos. Take your example:

export function itemsAction(items) {
    return {
        type: 'ITEMS',
        data: items
    }
}

Now let's say I have a reducer to handle that action that also uses a raw string:

const todos = (state = [], action) => {
  switch (action.type) {
    case 'ITESM':
      return state.map(item => item.something = "potato")
    default:
      return state
  }
}

In the reducer, I misspelled the action type for its case. But due to how Javascript and Redux work, it won't get noticed as an error in your IDE linting, nor will it produce any errors when you execute the code. You'll dispatch the action, and it will silently fail. Nothing will happen, no action, no errors, nothing. This can be a pain to debug.

In addition, what if you want to change the name of an action. It's good to just go change the value in the object, rather than do a big find and replace across your whole project, hoping you don't overwrite something you didn't mean to in the process.

Plus it's just nice to have all your action types in one place, so you can go through and see what you have available, rather than looking through all your action files. Once your project grows, you'll be glad you did it.

Also, on Typescript it's especially useful, since if you try to use an action you haven't defined it won't even build, so you get some build time safety.

Jayce444
  • 8,725
  • 3
  • 27
  • 43
  • 2
    "Plus it's just nice to have all your action types in one place, so you can go through and see what you have available, rather than looking through all your action files. Once your project grows, you'll be glad you did it." This bit right here is probably one of the more understated benefits to storing your types in a separate file. It creates a structure that shows you everything you have available which is especially efficient when working collaboratively. – Chris Ngo Jun 03 '19 at 06:46
1

This may be a duplicate of this question.

My answer though

Action types are going to be referred to several times in your code. For example, in your reducer, you may also refer to your action type:

import {
  types
} from './actions'

...

function exampleReducer(state, action) {
  switch (action.type) {
    case types.ITEMS:
       // do something here
    default:
      return state
  }
}

Then you don't want to write type: 'ITEMS' again there. You want to write types.ITEMS to avoid repeating yourself. It's always a good practice to refer to constant variables rather than writing them over again in plain strings.

Types get especially hard to remember when you have multiples of them and usages in multiple files. So it's really good for you to have action types as constants.

It's a good habit to see your action types in one file sorted out so that you can always have a look over it and change them as needed (as opposed to changing 'ITEMS' to 'ITEM' in your 4 files if you were to change the name of the action type).

ETC

You usually do something like

import {
  ITEMS,
  ...more action types
} from './actions'

and refer to it directly (which is more concise):

export function itemsAction(items) {
    return {
        type: ITEMS,
        data: items
    }
}
Joel Mun
  • 81
  • 4
1

It's beneficial to keep actions in a separate file because it reduces the code duplication. Your actions names will be required in actions, reducers (possibly multiple reducers) and epics (if you use redux-observable). Always copy-pasting action name string is error prone, you can easily end up with a typo.

If you put action names in a separate file, you can be more confident about using them in the system and refactoring later since you have a single point of truth.

If you decide to use TypeScript, try something like typesafe-actions. TypeScript eliminates the need for having action names in a separate constants file since action name can become a real type. This opens up a lot of things like having intellisense when writing actions in reducers and epics

  • +1 for typescript replacing this. When I hit this thread, I was thinking these const FOO = 'FOO'; is so dumb, but I'm very good about search/replace accurately. Indeed, typos can happen, but they can happen anywhere. I think this just goes to show how helpful type safety is. Special strings will inevitable creep in somewhere, having a variable for every one IMO is just a little crazy – Devin Rhode May 19 '20 at 21:35