Releases: react-boilerplate/redux-injectors
v2.1.0
🐛 Bug Fix
- Fixes TS typing for
createManager
so bothreducer
andsaga
are optional (See #36, thanks @mrfratello !) - Adds support for react 18 in peerDeps (See #42, thanks @partounian !)
v2.0.0
It’s been a long time coming, but redux-injectors 2.0 is here 🎉
This release contains some breaking changes and some new features. Unfortunately some breaking changes were needed in order to fix #19 .
For the announcement blog post, see this link.
💥 Breaking Changes
useInjectReducer
- Reducer injection now happens inside a
useLayoutEffect
instead of during the render. This means the following patterns will be broken:- A
useSelector
call after a call touseInjectReducer
will result inundefined
for the first render, if the selector tries to select from a piece of state that the reducer manages. If you need to do this, please make your selector resilient to undefined state. - An injected reducer will not receive a dispatch if that dispatch is made inside a
useLayoutEffect
inside a component further down the tree. This can be fixed by any of the following:- Use
useEffect
instead ofuseLayoutEffect
useInjectReducer
now returns a boolean indicating whether or not the reducer has finished injecting. This allows you to returnnull
if the boolean isfalse
instead of the component's children.- Use the new
createManager
API which does the above point for you
- Use
- A
useInjectSaga
- Saga injection now happens inside a
useLayoutEffect
instead of during the render. This means the saga will not catch a dispatch made inside auseLayoutEffect
inside a component further down the tree. This can be fixed in the same ways as explained in theuseInjectReducer
section - The default saga injection mode was changed to
COUNTER
. In this mode, the saga will be injected once at-least 1 component mounts that depends on this saga. The saga will be ejected once every component that depends on this saga un-mounts. This means multiple components can inject the saga, but the saga will only run once until every one of these components un-mounts. - The mode parameter for
useInjectSaga
was removed. The default and only possible mode for saga injection is nowCOUNTER
.
🚀 New Features
createManager
This is a new API that creates a "manager" component given a reducer and/or saga. Each manager will only render its children after both
the reducer and saga has been injected. You can almost think of managers like "providers" for reducers and sagas.
const BooksManager = createManager({ name: "BooksManager", key: "books", reducer: booksReducer, saga: booksSaga })
...
<BooksManager>
<BooksList />
</BooksManager>
This is now the recommended way to use redux-injectors
because it avoids some caveats with useInjectReducer
and useInjectSaga
.
COUNTER mode
The COUNTER
mode is a new saga injection mode, and the only mode used by useInjectSaga
. This mode is relevant when multiple useInjectSaga
are injecting the same saga. When the first useInjectSaga
injects, the saga will be run. Each subsequent useInjectSaga
will not re-run the saga. The saga will be ejected when the last component using the saga un-mounts.
In other words, this means multiple components can inject the saga, but the saga will only run once until every one of these components un-mounts. Thanks @goranurukalo for the contribution!
📝 Documentation
- A note was added to the documentation recommending to set
shouldHotReload: false
for redux dev tools. - An example app was added
v2.0.0-rc
This pre-release contains some breaking changes and some new features. Unfortunately some breaking changes were needed in order to fix #19 . Since this is a release candidate, please Install at your own risk. If you do install this version, please report any issues you find.
💥 Breaking Changes
useInjectReducer
- Reducer injection now happens inside a
useLayoutEffect
instead of during the render. This means the following patterns will be broken:- A
useSelector
call after a call touseInjectReducer
will result inundefined
for the first render, if the selector tries to select from a piece of state that the reducer manages. If you need to do this, please make your selector resilient to undefined state. - An injected reducer will not receive a dispatch if that dispatch is made inside a
useLayoutEffect
inside a component further down the tree. This can be fixed by any of the following:- Use
useEffect
instead ofuseLayoutEffect
useInjectReducer
now returns a boolean indicating whether or not the reducer has finished injecting. This allows you to returnnull
if the boolean isfalse
instead of the component's children.- Use the new
createManager
API which does the above point for you
- Use
- A
useInjectSaga
- Saga injection now happens inside a
useLayoutEffect
instead of during the render. This means the saga will not catch a dispatch made inside auseLayoutEffect
inside a component further down the tree. This can be fixed in the same ways as explained in theuseInjectReducer
section - The default saga injection mode was changed to
COUNTER
. In this mode, the saga will be injected once at-least 1 component mounts that depends on this saga. The saga will be ejected once every component that depends on this saga un-mounts. This means multiple components can inject the saga, but the saga will only run once until every one of these components un-mounts. - The mode parameter for
useInjectSaga
was removed. The default and only possible mode for saga injection is nowCOUNTER
.
🚀 New Features
createManager
This is a new API that creates a "manager" component given a reducer and/or saga. Each manager will only render its children after both
the reducer and saga has been injected. You can almost think of managers like "providers" for reducers and sagas.
const BooksManager = createManager({ name: "BooksManager", key: "books", reducer: booksReducer, saga: booksSaga })
...
<BooksManager>
<BooksList />
</BooksManager>
This is now the recommended way to use redux-injectors
because it avoids some caveats with useInjectReducer
and useInjectSaga
.
COUNTER mode
The COUNTER
mode is a new saga injection mode, and the only mode used by useInjectSaga
. This mode is relevant when multiple useInjectSaga
are injecting the same saga. When the first useInjectSaga
injects, the saga will be run. Each subsequent useInjectSaga
will not re-run the saga. The saga will be ejected when the last component using the saga un-mounts.
In other words, this means multiple components can inject the saga, but the saga will only run once until every one of these components un-mounts. Thanks @goranurukalo for the contribution!
📝 Documentation
- A note was added to the documentation recommending to set
shouldHotReload: false
for redux dev tools. - An example app was added
v1.3.0
v1.2.0
v1.0.0
🎉This is our first release of the redux-injectors
project 🎉
As some background, redux-injectors
was created by pulling out the injectors-related code from the main react-boilerplate repository.
This library lets you dynamically load redux
reducers and redux-saga
sagas as needed, instead of loading them all upfront. This has some nice benefits, such as avoiding having to manage a big global list of reducers and sagas. It also allows more effective use of code-splitting.