0

I am confused by the following code.

Source
export const createProject = (project) => {
  return (dispatch, getState, {getFirestore}) => {
    // make async call to database
    const firestore = getFirestore();
    firestore.collection('projects').add({
      ...project,
      authorFirstName: 'Net',
      authorLastName: 'Ninja',
      authorId: 12345,
      createdAt: new Date()
    }).then(() => {
      dispatch({ type: 'CREATE_PROJECT_SUCCESS' });
    }).catch(err => {
      dispatch({ type: 'CREATE_PROJECT_ERROR' }, err);
    });
  }
};

My question is about this line.

return (dispatch, getState, {getFirestore}) => {...

What makes this work? Where do the arguments come from? What calls them? Aren't all these arguments already in scope? Why do we need createProject to return a second function? Is createProject returning a second function? Or is it immediately invoking an inline function? What triggers the return function to run?

I'm just generally very confused by this pattern. Can someone please break it down for me?

Code-Apprentice
  • 81,660
  • 23
  • 145
  • 268
Let Me Tink About It
  • 15,156
  • 21
  • 98
  • 207
  • Presumably the caller of `createProject` is expecting a function returned and will call the returned function with the `dispatch, getState, {getFirestore}` arguments. `createProject` looks like a function factory (ish). – Carcigenicate Apr 18 '19 at 19:31
  • @VLAZ Isn't it only classified as currying if each function in turn only takes 1 argument itself? This doesn't strike me as currying, just a typical higher order function. – Carcigenicate Apr 18 '19 at 19:32
  • @Carcigenicate technically yes, but it's more formally tranforming `f(a, b, c)` into being evaluated into steps where each satisfies the parameter. Some implementations do only allow you to turn the steps into `f(a) -> g(b) -> h(c)` while others make it also possible to go with `f(a) -> g(b, c)`. Besides, I can't really find a better duplicate than the concept of currying. Surely once one has that down, the arity of the functions is irrelevant to the result. – VLAZ Apr 18 '19 at 19:37
  • Are you using redux here? – Code-Apprentice Apr 18 '19 at 21:17
  • @Code-Apprentice: Yes. Does that affect the answer? – Let Me Tink About It Apr 18 '19 at 21:42

2 Answers2

2

Starting with the simplest pattern:

function outter(outterArg) {
  return function(innerArg) {
     console.log(outterArg, innerArg  )
  }
}
let retFunction = outter('outterValue')
// retFunction is that function returned from outter
// now call the retFunction
retFunction('innerValue')

// or call them on one line
outter('oneLineOutter')('oneLineInner')
Jarek Kulikowski
  • 1,399
  • 8
  • 9
  • 1
    I'm personally hesitant to mark this as a duplicate of the currying post, but if you're just going to post a simple example of currying, it would have been better to just vote on VLAZ's dupe post which contains far more information. – Carcigenicate Apr 18 '19 at 19:41
  • close and redirect to https://stackoverflow.com/questions/36314/what-is-currying ? All this lad needed was that this method is called "currying", now he can do some proper googling! – MKougiouris Apr 18 '19 at 19:43
  • @Carcigenicate, Technically it is a duplicate, but this one is so quick and simple, some folks might like it. – Jarek Kulikowski Apr 18 '19 at 19:44
1

Where do the arguments come from?

Just like any other function, arguments are passed in when you call the function.

What calls them?

The returned function is called elsewhere. In this case, redux or react will call your createProject() function and get its return value. Then it will call the returned function with the appropriate parameters.

Why do we need createProject to return a second function?

Redux is full of this pattern where you have a function which returns another function.

Is createProject returning a second function?

Yes it is.

Or is it immediately invoking an inline function?

No it is invoked later.

What triggers the return function to run?

Redux eventually calls the returned function to run it.

Code-Apprentice
  • 81,660
  • 23
  • 145
  • 268
  • +1 but where, [in the source code linked here](https://github.com/iamshaunjp/React-Redux-Firebase-App/blob/lesson-18/marioplan/src/store/actions/projectActions.js) does Redux call the inner function to run it? – Let Me Tink About It Apr 20 '19 at 01:13
  • @Mowzer The inner function is not called anywhere in that code which you linked because it isn't the source code for redux. Rather it is a library which uses redux to connect to firebase. – Code-Apprentice Apr 21 '19 at 18:53