Skip to main content

Redux integration

Using redux is completely optional. However, for many it means easy integration or migration with existing projects, or just a nice centralized state management abstraction.

Integration is fairly straightforward as rest-hooks already uses the same paradigms as redux under the hood. However, care should be taken to integrate the reducer and middlewares properly or it won't work as expected.

First make sure you have redux installed:

npm install --save @rest-hooks/redux redux

Note: react-redux is not needed for this integration (though you will need it if you want to use redux directly as well).

Then you'll want to use the <ExternalCacheProvider /> instead of <CacheProvider /> and pass in the store and a selector function to grab the rest-hooks specific part of the state.

Note

You should only use ONE provider; nested another provider will override the previous.

Note

Rest Hooks manager middlewares return promises, which is different from how redux middlewares work. Because of this, if you want to integrate both, you'll need to place all redux middlewares after the PromiseifyMiddleware adapter, and place all Rest Hooks manager middlewares before.

index.tsx

import {
SubscriptionManager,
PollingSubscription,
ExternalCacheProvider,
PromiseifyMiddleware,
applyManager,
initialState,
createReducer,
NetworkManager,
Controller,
} from '@rest-hooks/redux';
import { createStore, applyMiddleware } from 'redux';
import ReactDOM from 'react-dom';

const networkManager = new NetworkManager();
const subscriptionManager = new SubscriptionManager(PollingSubscription);
const controller = new Controller();

const store = createStore(
createReducer(controller),
initialState,
applyMiddleware(
...applyManager([networkManager, subscriptionManager], controller),
// place Rest Hooks built middlewares before PromiseifyMiddleware
PromiseifyMiddleware,
// place redux middlewares after PromiseifyMiddleware
),
);
const selector = state => state;

// managers optionally provide initialization subroutine
for (const manager of [networkManager, subscriptionManager]) {
managers[i].init?.(selector(store.getState()));
}

ReactDOM.render(
<ExternalCacheProvider
store={store}
selector={selector}
controller={controller}
>
<App />
</ExternalCacheProvider>,
document.body,
);

Above we have the simplest case where the entire redux store is used for rest-hooks. However, more commonly you will be integrating with other state. In this case, you will need to use the selector prop of <ExternalCacheProvider/> to specify where in the state tree the rest-hooks information is.

// ...
const selector = state => state.restHooks;

const store = createStore(
// Now we have other reducers
combineReducers({
restHooks: restReducer,
myOtherState: otherReducer,
}),
applyMiddleware(
...mapMiddleware(selector)(
...applyManager([networkManager, subscriptionManager], controller),
),
PromiseifyMiddleware,
),
);
// ...

Here we store rest-hooks state information in the 'restHooks' part of the tree.

Redux devtools

Redux DevTools allows easy inspection of current state and transitions in the Rest Hooks store.

Simply wrap the return value of applyMiddleware() with composeWithDevTools()

import { composeWithDevTools } from 'redux-devtools-extension';

const store = createStore(
createReducer(controller),
initialState,
composeWithDevTools({
trace: true,
})(
applyMiddleware(
...applyManager([networkManager, subscriptionManager], controller),
// place Rest Hooks built middlewares before PromiseifyMiddleware
PromiseifyMiddleware,
// place redux middlewares after PromiseifyMiddleware
),
),
);