Search code examples
javascriptreduxredux-thunk

actions without an explicit type property


As you can see on this line of the Redux source code, actions must have a type property. In the real world example in the source code repository, there is an action like this, with no type property declared.

function fetchUser(login) { 
10   return { 
11     [CALL_API]: { 
12       types: [ USER_REQUEST, USER_SUCCESS, USER_FAILURE ], 
13       endpoint: `users/${login}`, 
14       schema: Schemas.USER 
15     } 
16   } 
17 } 

The CALL_API referred to is a JavaScript symbolhere

export const CALL_API = Symbol('Call API')

On a sidenote, from the Mozilla site, it appears that you access a symbol with array brackets

var sym = Symbol("foo");
var obj = {[sym]: 1};

So, back to the redux code, the middleware that handles the action without the explicit type seems to access the property created by the CALL_API...

export default store => next => action => { 
84   const callAPI = action[CALL_API] 
85   if (typeof callAPI === 'undefined') { 
86     return next(action) 
87   }  function fetchUser(login) { 
10   return { 
11     [CALL_API]: { 
12       types: [ USER_REQUEST, USER_SUCCESS, USER_FAILURE ], 
13       endpoint: `users/${login}`, 
14       schema: Schemas.USER 
15     } 
16   } 
17 } 

Going back to the first code cited above, if I remove the array brackets from around the call api like this

 function fetchUser(login) { 
    10   return { 
    11     CALL_API: { 

I get the error, "Actions may not have an undefined "type" property".

Question: how does the (correct) use of the symbol in the fetchUser function, for example, satisfy the requirement for a type property on the action?


Solution

  • Using brackets in an object literal is part of the newer ES6 syntax. It lets you define a key in an object using an expression, which could include the value of a variable:

    const keyName = "test";
    const obj = { [keyName + "Key"] : 42};
    // result: { "testKey" : 42}
    

    Symbols can also be used as object keys (see http://blog.keithcirkel.co.uk/metaprogramming-in-es6-symbols/ ) for some explanation.

    When you put the brackets around [CALL_API], you're saying "use the value of the CALL_API variable as the key". When you don't use brackets, you're saying "Use the literal string "CALL_API" as the key name".

    The middleware is then looking for an action object which has a key correctly matching the CALL_API symbol. When it sees one, it stops it, and does not pass it onwards to the reducers. So, when you remove the brackets, you're instead dispatching an action that looks like {"CALL_API" : {} }. That doesn't match what the middleware is looking for, it does reach the reducers, and then the type check fails.