Skip to content

Releases: jeffbski/redux-logic

v0.10.0

18 Nov 19:22
Compare
Choose a tag to compare

Possible breaking changes

It is unlikely that these changes would introduce problems in most codebases but since there is a possibility so I wanted to call them out.

  • Several methods now throw errors if passed logic that is duplicated (same exact instance) since this is most likely a misconfiguration in your code. You can clone the logic with Object.assign or similar to create multiple instances if you really need to have the same logic multiple times in the stack.
    • createLogicMiddleware(arrLogic, deps) - arrLogic is expected to have unique logic instances
    • logicMiddleware.addLogic(arrLogic) - arrLogic needs to be unique and not contain any instances that were already present in the logic stack
    • logicMiddleware.replaceLogic(arrLogic) - arrLogic needs to be unique instances
  • A new method is added which will check the array of logic and only merge in new items was added. This makes it easy to work with split bundles. If the logic already exists in the stack then it will be filtered out of the merge so only new items are added.
    • logicMiddleware.mergeNewLogic(arrLogic) - will check whether logic already exists in the stack merging only the new ones into the stack.
  • Use arity of process fn signature to determine the default dispatching mode (single, multiple, dispatchReturn) to make use more intuitive.

With v0.10.0 process has the following fn signature

process({ getState, action }, ?dispatch, ?done)

which results in the following three possible variations:

// dispatch from returned object, resolved promise, or observable
// this defaults processOptions.dispatchReturn = true enabling
// dispatching of the returned/resolved values
process({ getState, action }) {
  return objOrPromiseOrObservable;
}
// single dispatch
process({ getState, action }, dispatch) {
  dispatch(objOrPromiseOrObservable); // call exactly once
}
// multiple dispatch, call done when finished dispatching
// this defaults processOptions.dispatchMultiple = true
// which enables the multiple dispatch mode
process({ getState, action }, dispatch, done) {
  dispatch(objOrPromiseOrObservable);
  dispatch(objOrPromiseOrObservable);
  done(); // call when done dispatching
}

Basically the arity of the function you provide for process determines the default values for a couple processOptions: dispatchReturn and dispatchMultiple. You can still set these values directly or just let them be inferred by the arity of process.

There is more discussion in the advanced section of the API docs.

Note: the previous v0.9 mechanism for multiple dispatches setting the second parameter of the dispatch function to {allowMore: true} will also work but is deprecated in lieu of this simpler arity approach.

New features

  • logic name property can be used to provide a meaningful name to logic. This property defaults to L(actionType)-idx if one is not provided. Technically name was already available but it wasn't documented until now.
  • processOptions.dispatchMultiple - drives whether process is in single dispatch mode or multiple dispatch mode. When false, it is single dispatch mode, dispatch is expected to be called exactly once and when true, multi-dispatch mode is enabled where dispatch can be used any number of times until the done cb is called to complete. The default is driven by whether the process fn has the done parameter. See the advanced section of the API for more details.
  • logicMiddleware.whenComplete(fn) - for server-side use, logicMiddleware can let you know when all your dispatched actions and all their processing has completed so you can serialize the state and send it to the server.
// for server-side use, runs optional fn and returns promise
// when all in-flight processing/loading has completed.
// Use it after performing any required store.dispatch
store.dispatch(ROUTE_CHANGE); // triggers async loading in our logic
store.dispatch(FOO); // any number of additional dispatches
return logicMiddleware.whenComplete(() => { // returns promise
  return store.getState(); // can serialize store, loading was done
});
  • logicMiddleware.monitor$ - observable for monitoring the internal operations inside all of your logic which is useful for debugging, testing, and for developing developer tools. More details in the advanced part of the API docs.

Migration instructions

  • You can check that your createLogicMiddleware, addLogic, and replaceLogic don't try to add the same logic refs multiple times or just check for an error when you run your tests. It will indicate which logic instances are duplicates. If you really do need duplicates then make a clone with Object.assign or similar.
  • If you are using { allowMore: true } for multiple dispatching, it is recommended to switch to the more intuitive approach using the additional done cb. The old way will likely continue to work since it is also used internally, but it is deprecated and you should change to the new style. Migrating involves taking out the { allowMore: true} and adding a call to the done cb when you are finished.
// since done is included in signature, multi-dispatch mode is enabled
// sets the default for processOptions.dispatchMultiple = true
process({ getState, action }, dispatch, done) {
  dispatch(foo);
  dispatch(bar); // dispatch any number of times
  done(); // when done dispatching
}
  • If you are using processOptions.dispatchReturn = true to dispatch the return obj, resolved promise or observable, then simply by omitting the dispatch from your process fn you will set the default dispatchReturn to true. Thus you don't have to specifically set dispatchReturn to true. It is fine to leave the code in but it is unnecessary as long as your fn signature omits the dispatch.
processOptions: {
  successType: FOO_SUCCESS, // optionally use this success action type/creator
  failType: FOO_FAILED // optionally use this fail action type/creator
},

// simply by omitting dispatch, we set the default for dispatchReturn to true
process({ getState, action }) {
  return objOrPromiseOrObservable; // returned or resolved value(s) will be dispatched
}

v0.9.3

01 Sep 18:01
Compare
Choose a tag to compare

The process hook's dispatch now returns the value passed to it. Useful in promise chains. Previously it returned nothing.

v0.9.1

24 Aug 19:00
Compare
Choose a tag to compare

Added live search examples using debounce and take latest functionality.

v0.9.0

23 Aug 21:01
Compare
Choose a tag to compare

Allow debounce, throttle, and latest to be used in combination. Original code would throw an error if debounce or throttle was used in conjunction with latest in logic, but now this is allowed.

Also I have reversed the order in which debounce and throttle are applied, first debouncing is applied, then throttling which I believe aligns best with most use cases.

v0.8.4

18 Aug 21:45
Compare
Choose a tag to compare

Clarify cancellation and take latest functionality and its relation to XHR abort in API doc. Add jsfiddle and full examples using RxJS Ajax which redux-logic can immediately abort on cancellation rather than simply suppressing the dispatch (as with http libraries that don't support in-flight cancellation).

v0.8.3

16 Aug 19:16
Compare
Choose a tag to compare

Documentation and new examples. Added some processOptions examples. Updated SAM/PAL section of README discussing the details of how redux-logic helps with the implementation of this pattern.

v0.8.2

15 Aug 22:10
Compare
Choose a tag to compare

Bug fix, missing catch method in the custom rxjs observable. Use this release or greater to work with processOptions feature. Added a full example for processOptions use.

v0.8.1

15 Aug 22:08
Compare
Choose a tag to compare

Note: use v0.8.2+ since the custom rxjs observable in this commit was missing the catch operator, fixed in 0.8.2

Added new option processOptions which influences the behavior of the process hook. It basically allows additional declaration to eliminate additional clutter in your code.

If you set the processOptions object, you can further influence how process behaves streamlining your code.

  • processOptions.dispatchReturn - if true, then process will use the returned value to dispatch. If you return a promise then it will use the resolve/reject values for dispatching. If you return an observable then it will use its values or error for dispatching. Returning an undefined, promise that resolves to undefined, or observable value of undefined will cause no dispatch. Default is false.
  • processOptions.successType - if set to an action type string or an action creator function it will use this to create the action from the dispatched value. If the successType was a string then it will create an action of this type and set the payload to the dispatched value. If it was an action creator function then it will pass the value to the action creator and then dispatch that. Default undefined.
  • processOptions.failType - if set to an action type string or an action creator function it will use this to create the action from the dispatched error or rejected promise value or errored observable similar to how successType works. If failType is not defined and an error is thrown or dispatched that does not itself have a type (action type), then an UNHANDLED_LOGIC_ERROR will be dispatched with the error as the payload. Default undefined.

An example of using processOptions:

const logic = createLogic({
  type: FOO,
  processOptions: {
    dispatchReturn: true,       // use my return for dispatch
    successType: 'FOO_SUCCESS', // my action type for success
    failType: 'FOO_ERROR',      // my action type for failure
  },
  process({ getState, action }) {
    // no need to dispatch when using dispatchReturn: true
    // actions are created from the resolved or rejected promise
    return axios.get('https://server/api/users')
      .then(resp => resp.data.users); // select the data
  }
}

v0.8.0

14 Aug 03:54
Compare
Choose a tag to compare

Slight interface change, createLogic will now only accept either validate or transform since they now both refer to the same hook internally. Both aliases have been kept to help communicate the intent of the logic being used, though either can do the same things. So there are basically 2 hooks now validate/transfer and process. The internal code was greatly simplified in this change, I couldn't find a reason to justify the extra complexity. None of my non-test examples ever used both validate and transfer in the same logic so I doubt that this should be much of a problem. The migration path is simply to move all the logic into the validate or transform hook.

More documentation updates and a few jsfiddle async await examples and a full async await example were added.

v0.7.4

12 Aug 18:57
Compare
Choose a tag to compare

Minor internal refactoring to ensure no artificial delays were introduced by the validate and translate hooks. Synchronous code will stay synchronous. Added another jsbin example and a few other examples including a notification example. Added more to docs and started adding more jsdoc.