redux-cookies-middleware is a Redux middleware which watches for changes in Redux state & stores them in browser cookie.
yarn add redux-cookies-middleware
or
npm i redux-cookies-middleware --save
import { applyMiddleware, createStore, compose } from 'redux';
import reduxCookiesMiddleware from 'redux-cookies-middleware';
import getStateFromCookies from 'redux-cookies-middleware/getStateFromCookies';
// initial state
let initialState = {
auth: {
token: 'xxxx',
key: 'xxx'
},
session: 'xxx-xxx'
};
// state to persist in cookies
const paths = {
'auth.token': { name: 'my_app_token' },
'session': { name: 'my_app_session' }
};
// read stored data in cookies and merge it with the initial state
initialState = getStateFromCookies(initialState, paths);
// create store with data stored in cookies merged with the initial state
const store = createStore(
reducer,
initialState,
applyMiddleware([
reduxCookiesMiddleware(paths)
])
);
An object of parts of subsets to sync. Use dot-notation to specify the path of the subsets of the store that has to be synced with cookies. Consider a store with the following shape as an example:
{
auth: {
token: 'xxxx',
key: 'xxx'
},
session: 'xxx-xxx',
username: 'xxxxxxx'
}
To sync the auth token
and session
with cookies, pass the following paths
object to the middleware:
{
session: {
name: 'session' // name of the cookie in which the value of session will be synced
},
'auth.token': {
name: 'auth_token' // name of the cookie in which the value of auth.token will be synced
}
}
Value of the path object is another object that takes more configuration options:
Property | Required | Type | Default | Description |
---|---|---|---|---|
name | Yes | String | Name of the cookie in which the part of the store should be synced. | |
equalityCheck | No | Function | options.defaultEqualityCheck |
A function to verify if the value before an action is dispatched and after the action is dispatched is equal or not. If the values are equal, the part of the store is not synced with the cookie. This is just to avoid setting cookies again and again if the value of that part of the store has not changed. You can set a custom equality check for every part of the store you want to sync with the cookies. Default value for this property is the value set for options.defaultEqualityCheck . |
deleteCheck | No | Function | options.defaultDeleteCheck |
A function to verify if the cookie should be deleted. Default value for this property is the value set for options.defaultDeleteCheck . |
import isEqual from 'lodash.isequal';
// initial state
let initialState = {
auth: {
token: 'xxxx',
key: 'xxx'
},
session: 'xxx-xxx'
};
const paths = {
session: {
name: 'session'
},
'auth.token': {
name: 'auth_token',
equalityCheck: isEqual
}
};
// read stored cookies into store
initialState = getStateFromCookies(initialState, persistCookies);
const store = createStore(
reducer,
initialState,
applyMiddleware([
reduxCookiesMiddleware(paths)
])
);
An object of common options for the middleware.
options
object has the following properties:
Property | Required | Type | Default |
---|---|---|---|
logger | No | Function | console.error |
setCookie | No | Function | A function that creates the cookie. |
defaultEqualityCheck | No | Function | A function that does shallow equality check. |
defaultDeleteCheck | No | Function | A function that performs undefined check. |
Description of each property:
logger(msg)
: This function can be used to capture errors occured insideredux-cookies-middleware
. A good use-case for this could be to capture these errors and log them to Sentry or Errorception.- This function has the following parameters:
msg
: Message you want to log with the help of this function.
- This function has the following parameters:
setCookie(name, value, [, expiry, secure])
: A function that creates the cookie. Provide a custom cookie setting implementation. Use-cases of this are implementation of cookie versioning or using the common cookie setting logic in your application. You will have to use a custom implementation ofgetCookie
as well.- This function has the following parameters:
name
: Name of the cookie.value
: Value of the cookie.expiry
(optional): Expiry time (in days) of the cookie. Default: 365 days.secure
(optional): Either true or false, indicating if the cookie transmission requires a secure protocol (https). Default: false.
- This function has the following parameters:
defaultEqualityCheck(oldVal, newVal)
: A function to verify if the value before an action is dispatched and after the action is dispatched is equal or not. If the values are equal, the part of the store is not synced with the cookie. This is just to avoid setting cookies again and again if the value of that part of the store has not changed. You can set a custom equality check for every part of the store you want to sync with the cookies. Default value for this property is a function which does shallow comparison of two values using the===
operator.- This function has the following parameters:
oldVal
: Value of the part of the store before the reducers for a particular action execute.newVal
: Value of the part of the store after the reducers for a particular action execute.
- Returns:
Boolean
-true
ifoldVal
andnewVal
are equal.
- This function has the following parameters:
defaultDeleteCheck(oldVal, newVal)
: A function to verify if the cookie should be deleted. The default value for this property is a function that checks if the value isundefined
.- This function has the following parameters:
oldVal
: Value of the part of the store before the reducers for a particular action execute.newVal
: Value of the part of the store after the reducers for a particular action execute.
- Returns:
Boolean
-true
if the cookie should be deleted.
- This function has the following parameters:
import Raven from 'raven';
const paths = { ... };
const setCookie = (name, value) => {
// Add your custom implementation for setting cookie
};
const logger = msg => {
// Log to Sentry
Raven.captureException(msg);
};
const defaultEqualityCheck = lodash.isEqual;
const defaultDeleteCheck = val => val === null;
const customOptions = {
logger,
setCookie,
defaultEqualityCheck,
defaultDeleteCheck,
};
reduxCookiesMiddleware(paths, customOptions);
getStateFromCookies
can be used to hydrate the store with the data synced with the cookies. It basically takes initialState
, reads the synced state from cookies and merges it with the initial state of your application.
It returns the initialState
merged with the state synced with cookies.
initialState
is the initial state object of your application.
paths
is the configuration of paths to sync with cookies as used with reduxCookiesMiddleware
.
getCookie()
is a function that reads a cookie. Provide a custom cookie reading implementation. Use-cases of this are implementation of cookie versioning or using the common cookie setting logic in your application. You would want to use it if you are using a custom implementation of setCookie
.
- This fucntion has the following parameters:
name
: Name of the cookie to read
- Returns: expected value of the part of the store synced with the cookie.
While using redux-cookies-middleware
with server-side rendering, we will have to override the default implementation of getCookie
and setCookie
functions to be able to read from cookie headers and send appropriate Set-Cookie
headers to the browser.
Consider this detailed example:
import express from 'express';
import cookieParser from 'cookie-parser';
import { applyMiddleware, createStore, compose } from 'redux';
import reduxCookiesMiddleware from 'redux-cookies-middleware';
import getStateFromCookies from 'redux-cookies-middleware/getStateFromCookies';
// state to persist in cookies
const paths = {
'auth.token': { name: 'my_app_token' },
'session': { name: 'my_app_session' }
};
// reads a cookie from the express request object.
const getCookieOnServer = (req, name) => req.cookies[name];
// sets cookie using the express response object.
const setCookieOnServer = (res, name, value) => {
res.cookie(name, value);
};
const app = express();
app.use(cookieParser()); // required to parse cookie headers into a Javascript object
app.get('/', (req, res) => {
// initial state
let initialState = {
auth: {
token: 'xxxx',
key: 'xxx'
},
session: 'xxx-xxx'
};
// read stored data in cookies and merge it with the initial state
initialState = getStateFromCookies(initialState, paths, (name, value) => getCookieOnServer(req, name));
// create store with data stored in cookies merged with the initial state
const store = createStore(
reducer,
initialState,
applyMiddleware([
reduxCookiesMiddleware(
paths,
{
setCookie: (name, value) => setCookieOnServer(res, name, value)
}
)
])
);
res.send('Hello world!');
});
yarn
ornpm install
to install npm development dependencies.yarn build
ornpm run build
will compile the source into dist.yarn test
ornpm run test
will run the unit test suit.yarn lint
ornpm run lint
will run eslint linting check.