jeffbski / redux-logic

Redux middleware for organizing all your business logic. Intercept actions and perform async processing.
MIT License
1.81k stars 107 forks source link

Add ability to transform deps before transform/validate/process #84

Open raygesualdo opened 6 years ago

raygesualdo commented 6 years ago

Hey Jeff! We've run into a situation where it would be helpful to transform our dependencies before they actually hit the process method. Essentially, I would like to have an additional dependency that contains pre-populated values from the current state and action (things like the user context, specific values optionally passed in via an action's meta field, etc.). Right now we're doing the extraction in each process call, which isn't very DRY.

I was thinking about how to accomplish this and my thought is to add a mapDeps (name TBD) function as the third argument in createLogicMiddleware. Then, that function would run here each time. An example of what this looks like could be:

    const depObj = {
      ...mapDeps(deps, getState, action),
      cancelled$,
      ctx: {}, // for sharing data between hooks
      getState,
      action
    };

mapDeps would be written by the user (defaulting to the identity function if not provided) and could look like this:

function mapDeps(deps, getState, action) {
  return {
    ...deps,
    someValue: get(getState(), 'some.deeply.nested.value.in.my.store')
  }
}

If you think this is a good idea and approach, I can submit a PR to get this worked in.

jeffbski commented 6 years ago

Ray,

Thanks for reaching out. I'm onsite right now, but I'll give it some thought and then we can greenlight the approach.

Will get back to you soon. Thanks.

Jeff

On Thu, Nov 2, 2017 at 9:52 AM Ray Gesualdo notifications@github.com wrote:

Hey Jeff! We've run into a situation where it would be helpful to transform our dependencies before they actually hit the process method. Essentially, I would like to have an additional dependency that contains pre-populated values from the current state and action (things like the user context, specific values optionally passed in via an action's meta field, etc.). Right now we're doing the extraction in each process call, which isn't very DRY.

I was thinking about how to accomplish this and my thought is to add a mapDeps (name TBD) function as the third argument in createLogicMiddleware. Then, that function would run here https://github.com/jeffbski/redux-logic/blob/d8d6424d74a83c07840ebc532a8768d5cacb8d3e/src/createLogicAction$.js#L194 each time. An example of what this looks like could be:

const depObj = {
  ...mapDeps(deps, getState, action),
  cancelled$,
  ctx: {}, // for sharing data between hooks
  getState,
  action
};

mapDeps would be written by the user (defaulting to the identity function if not provided) and could look like this:

function mapDeps(deps, getState, action) { return { ...deps, someValue: get(getState(), 'some.deeply.nested.value.in.my.store') }

If you think this is a good idea and approach, I can submit a PR to get this worked in.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/jeffbski/redux-logic/issues/84, or mute the thread https://github.com/notifications/unsubscribe-auth/AAAWOZSBW1y9p0RBQ2buW4KF1UBOBzeBks5sydc9gaJpZM4QP0BA .

-- Jeff Barczewski Founder of CodeWinds http://codewinds.com/ Live and Online developer training

raygesualdo commented 6 years ago

Sounds great!

Another idea I had was to allow deps to also be a function (which is passed getState and action) that returns an object. That way there's no need to have another argument in createLogicMiddleware or to explain what mapping over dependencies involves. deps is either an object or a function that returns an object. I think I like this way better. 😃

KevinAst commented 6 years ago

@raygesualdo ... I too think your second approach (allowing deps to be a function) is a much cleaner approach!

jeffbski commented 6 years ago

Thanks @raygesualdo and @KevinAst! I think the second approach sounds the best to me too.

If deps is a function then it would be providing the resulting dependency structure after doing whatever transformation is desired.

Since this is a fair number of arguments to pass into the deps function, I'm thinking it should come in as an object containing all the built-in deps and then a new object can be returned with any overrides, additions, etc.

So createLogicMiddleware(arrLogic, deps) and also logicMiddlware.addDeps(deps) would allow functions as an alternative to the objDeps. In the second case addDeps(fnDeps) would basically supercede the previous dep fn or would both be called in order?

The deps fn signature in either case would be

// return the transformed/augmented deps
const deps = builtinDepsObj => ({
  ...builtinDepsObj,
  foo: 123,  // adding in new
  bar: builtinDepsObj.bar * 100    // overriding previous
});

How does that sound? and what should be the flow if addDeps(depfn) is called one or more times. Will they chain together or completely replace any previous one? I guess since the function is named addDeps and it was traditionally always appending to, it seems like addDeps would also append to the chain calling any previous depFns before calling itself.