Skip to content

Releases: ctrlplusb/easy-peasy

v2.1.0

16 Mar 21:28
Compare
Choose a tag to compare

Minor Changes

  • Adds the ability to provide custom store enhancers: a69baa7

Patches

  • Fix for typescript Action type to allow no payload: 3f981f1
  • Adss missing thunkFailName helper: 4795277

v2.0.1

14 Mar 00:28
Compare
Choose a tag to compare

Patches

  • Fixes support for index signatures in state: 82a530e

v2.0.0

12 Mar 18:30
Compare
Choose a tag to compare

The V1 API finally reached a place where any significant new features/changes would become a breaking change. In order to avoid breaking change fatigue we have tried to group all the breaking changes we would like to make in this singular v2 release, whilst ensuring that the migration path from v1 to v2 would not be painful. The breaking changes are detailed below along with the changes required to upgrade.

Some of the highlights of v2 includes:

  • Rewrites internals, optimising it dramatically, including an optimisation fix on selectors
  • thunks that are fired and will be displayed in redux dev tools to indicate the started/completed/failed states of them
  • Allows models to be dynamically added/removed to the store.
  • Removes APIs that were announced as deprecated in v1
  • Allows the listen implementations to trigger an action or a thunk
  • Introduces an action helper and requires that actions be declared using this helper
  • Changes thunk helper API. getState now returns local state to thunk. Added getStoreState which returns full store state.

You will need to follow the notes for the breaking changes below if upgrading a v1 project to v2. We have tried to output helpful console messages where we can to help with this migration.

New Feature: Thunk action firing

In v1 we would dispatch actions to represent the start/complete of a thunk. This was done with the intention of aiding debugging only, and was disabled if you disabled dev tools via the createStore config.

We have decided to make these action dispatches an official part of the API. They are now guaranteed to fire even if the dev tools are disabled. In addition to this we have introdcued a third type of action that can fire; specifically if a thunk fails. If an error is thrown in the processing of one of your thunks an action will fire to indicate that this is the case. The action will contain an additional parameter called error, which will be an object containing the message and stack of the error.

const store = createStore({
  doSomething: thunk(async () => {
    throw new Error('oh noes');
  }),
});

// Dispatching this thunk action results in a failure
store.dispatch.foo.doSomething('hi');

// Check your dev tools and you should see actions dispatched like this:
// [
//   { type: '@thunk.doSomething(started)', payload: 'hi' },
//   { 
//     type: '@thunk.doSomething(failed)', 
//     payload: 'hi', 
//     error: { message: 'oh noes', stack: '...' } 
//   }
// ]

New Feature: Dynamically add/remove models to/from your store

This is in response to #29, where the request was made to be able to dynamically add models, which can help for advanced/large applications that are code split.

We have added two new APIs which get exposed on the store allowing you to do this.

const store = createStore({
  counter: {
    count: 0,
  },
});

// Adding a model
store.addModel('todos', {
  items: [],
  add: action((state, payload) => {
    state.items.push(payload);
  })
});

// You can now use the newly added model
store.getState().todos.items;
store.dispatch.todos.add('Upgrade to v2');

// You can also remove models
store.removeModel('todos');

Breaking Change: Actions

Previous way of defining actions (v1):

const model = {
  count: 0,
  increment: (state) => {
    state.count += 1;
  }
};

New way of defining actions (v2):

import { action } from 'easy-peasy';

const model = {
  count: 0,
  increment: action((state) => {
    state.count += 1;
  })
};

Breaking Change: Listeners

Previous way of defining listeners (v1):

import { listen, action } from 'easy-peasy';

const notificationModel = {
  msg: '',
  set: action((state, payload) => {
    state.msg = payload;
  }),
  listeners: listen((on) => {
    //                         👇 previous syntax
	on(userModel.register, (actions) => {
       actions.set('User logged in');
    });
  })
};

New way of defining listeners (v2):

import { listen, thunk } from 'easy-peasy';

const notificationModel = {
  msg: '',
  set: action((state, payload) => {
    state.msg = payload;
  }),
  listeners: listen((on) => {
    //                      👇 new syntax
	on(userModel.register, thunk((actions) => {
       actions.set('User logged in');
    }));
  })
};

As you can see you explicitly have to declare the handler as a thunk. V2 also allows you to declare your listeners as an action:

import { listen, thunk } from 'easy-peasy';

const notificationModel = {
  msg: '',
  listeners: listen((on) => {
    //                      👇 new syntax
	on(userModel.register, action((state) => {
       state.msg = 'User logged in';
    }));
  })
};

This can be useful as an alternative syntax, producing more concise code.

Breaking Change: Thunk getState/getStoreState

We have updated the helpers API for thunks. The getState helper on a thunk will now return the local state at where the thunk is mounted. An additional helper named getStoreState has been added which will continue to return the full store state.

This is an improvement with the intention of allowing models to be more self contained. It promotes better testability and allows for easier writing of helpers that you can use to boostrap models.

In order to fix your code...

Before:

import { thunk } from 'easy-peasy';

const model = {
  counter: {
    count: 0,
    doSomething: thunk((actions, payload, { getState }) => {
      getState().counter.count
    })
  }
};

After:

import { thunk } from 'easy-peasy';

const model = {
  counter: {
    count: 0,
    doSomething: thunk((actions, payload, { getState }) => {
      getState().count
    })
  }
};

Or if you need state from another branch of your model:

import { thunk } from 'easy-peasy';

const model = {
  user: {
    name: 'bob'
  },
  audit: {
    doSomething: thunk((actions, payload, { getStoreState }) => {
      getStoreState().user.name
    })
  }
};

We don't recommend reaching across models though, and instead recommend using listeners instead.

v1.14.0

13 Feb 13:41
Compare
Choose a tag to compare

Minor Changes

  • Adds testing helpers: #88

Patches

  • Updates dev deps: 84cd654
  • Fixes build in logFullState thunk: 23ffd9b

Thanks to @ifyoumakeit for the help!

v1.13.5

13 Feb 07:04
Compare
Choose a tag to compare

Patches

  • Cleans up package json: 4852c0f
  • Update deprecated effect to thunk: #91
  • Fixes not being able to listen to thunks: 3a2a966

Credits

Huge thanks to @homura for helping!

v1.13.0

11 Feb 23:52
Compare
Choose a tag to compare

Minor Changes

  • Adds string action listen: 639a4ac

Chores

v1.12.2

09 Feb 23:33
Compare
Choose a tag to compare

Patches

  • Adjusts UMD build output to target >= IE 11: 98fdd59
  • Fixes State and Action recursive types: #78

Chores

v1.12.1

07 Feb 23:46
Compare
Choose a tag to compare

Patches

  • Fixes actions definitions: 714da43

v1.12.0

07 Feb 23:01
Compare
Choose a tag to compare

Minor Changes

Chores

v1.11.1

07 Feb 00:52
Compare
Choose a tag to compare

Chores