The list of all available functions from the redux-detector
package.
Creates new StoreDetectableEnhancer
that can be passed as a second or third parameter of the
createStore
function from redux
. This enhancer hooks into store's dispatch
method
and adds replaceDetector
method. You can pass second argument which is a listener that will
be called with dispatch result (value returned by calling dispatch
) or dispatch error.
Example:
import { createStore } from "redux";
import { createDetectorEnhancer } from "redux-detector";
import { rootReducer } from "./store/rootReducer";
import { rootDetector } from "./store/rootDetector";
const store = createStore(rootReducer, createDetectorEnhancer(rootDetector));
Creates new DetectorListener that can be passed as a second argument of the createDetectorEnhancer
function. A listener allows to handle all dispatch results and errors done by redux-detector
.
Functions onNext
and onError
receives three arguments: result
/error
, action
, and api
which
is an object: { dispatch, getState }
- same as middleware API.
Example:
import { createStore } from "redux";
import { createDetectorEnhancer, createDetectorListener } from "redux-detector";
import { rootReducer } from "./store/rootReducer";
import { rootDetector } from "./store/rootDetector";
import { openSnackbar } from "./store/snackbarAction";
const detectorListener = createDetectorListener(
(result, action, { dispatch }) => {
if (result instanceof Promise) {
result
.then(asyncResult => console.log({ asyncResult, action }))
.catch(asyncError => {
console.error({ asyncError, action });
dispatch(openSnackbar("Unknown error occurred"));
});
} else {
console.log({ result, action });
}
},
(error, action, { dispatch }) => {
console.error({ error, action });
dispatch(openSnackbar("Unknown error occurred"));
}
);
const store = createStore(
rootReducer,
createDetectorEnhancer(rootDetector, detectorListener)
);
Composes many DetectorListener
s into one DetectorListener
. Listeners will be called in the
same order as passed to this function.
Example:
import { createStore } from "redux";
import {
createDetectorEnhancer,
createDetectorListener,
composeDetectorListeners
} from "redux-detector";
import { rootReducer } from "./store/rootReducer";
import { rootDetector } from "./store/rootDetector";
import { openSnackbar } from "./store/snackbarAction";
const detectorConsoleListener = createDetectorListener(
(result, action) => {
if (result instanceof Promise) {
result
.then(asyncResult => console.log({ asyncResult, action }))
.catch(asyncError => console.error({ asyncError, action }));
} else {
console.log({ result, action });
}
},
(error, action) => {
console.error({ error, action });
}
);
const detectorSnackbarListener = createDetectorListener(
(result, action, { dispatch }) => {
if (result instanceof Promise) {
result.catch(() => dispatch(openSnackbar("Unknown error occurred")));
}
},
(error, action, { dispatch }) => {
dispatch(openSnackbar("Unknown error occurred"));
}
);
const detectorListener = composeDetectorListeners(
detectorConsoleListener,
detectorSnackbarListener
);
const store = createStore(
rootReducer,
createDetectorEnhancer(rootDetector, detectorListener)
);
Features like hot-reloading or code splitting requires hooks to update rootDetector.
You can do it via replaceDetector
method available on an enhanced store.
Hot reloading example:
if (module.hot) {
module.hot.accept("./store/rootReducer", async () => {
const {
rootReducer: nextRootReducer
} = await import("./store/rootReducer");
store.replaceReducer(nextRootReducer);
});
module.hot.accept("./store/rootDetector", async () => {
const {
rootDetector: nextRootDetector
} = await import("./store/rootDetector");
store.replaceDetector(nextRootDetector);
});
}
These functions are building blocks for creating more complex detectors. There is no hidden magic in these functions - they are simple and pure.
Composes many actions detectors into one actions detector. If some of detectors returns an action or a list of actions, they are merged into one list of actions.
Example:
import { composeDetectors } from "redux-detector";
import { userDetector } from "./user/userDetector";
import { companyDetector } from "./company/companyDetector";
export const rootDetector = composeDetectors(userDetector, companyDetector);
Combines many actions detectors into one actions detector. The logic behind is the same
as in the combineReducers
function.
Example:
import { combineDetectors } from "redux-detector";
import { blockUser } from "./userActions";
export const blockUserOnLoginAttemptsExceededDetector = combineDetectors({
login: combineDetectors({
attempts: (prevAttempts, nextAttempts) =>
prevAttempts < 3 && nextAttempts >= 3 ? blockUser() : undefined
})
});
Composes many condition detectors into one condition detector using and
operation on
detectors output.
Example:
import { composeAnd, isTruthy } from "redux-detector";
import { exceededLoginLimit } from "./userDetector";
import { isOnAdminZone } from "../security/securitySelector";
export const exceededLimitOnAdminZone = composeAnd(
isTruthy(isOnAdminZone),
exceededLoginLimit
);
Composes many condition detectors into one condition detector using or
operation on
detectors output.
Example:
import { composeOr } from "redux-detector";
import { exceededLoginLimit, exceededResetPasswordLimit } from "./userDetector";
export const exceededLoginOrResetPasswordLimit = composeOr(
exceededLoginLimit,
exceededResetPasswordLimit
);
Creates actions detector that runs inner actions
detector only if condition
detector
output is truthy.
Example:
import { composeIf } from "redux-detector";
import { exceededLoginLimit } from "./userDetector";
import { blockUser } from "./userActions";
const blockUserOnExceededLimitDetector = composeIf(exceededLoginLimit, () =>
blockUser()
);
Maps state passed to a detector by selector - works perfectly with reselect library.
Example:
import { mapDetector, changedToTruthy } from "redux-detector";
import { getLoginAttempts } from "./userSelector";
export const exceededLoginLimitDetector = mapDetector(
getLoginAttempts,
changedToTruthy(attempts => attempts > 3)
);
Maps previous state passed to a detector by selectors - works perfectly with reselect library.
It's a shortcut for mapDetector(createSelector(...selectors), (prevState) => prevState)
.
Analogous to the mapPrevState
.
Creates condition detector that checks if next state is not equal previous state (uses ===
operator)
Example:
import { composeIf, changed } from "redux-detector";
import { getUserId } from "./userSelector";
import { fetchUser } from "./userAction";
export const fetchUserDetector = composeIf(changed(getUserId), () =>
fetchUser()
);
Same as changed
with additional requirement - next state has to be truthy.
Same as changed
with additional requirement - next state has to be falsy.
Same as changed
with additional requirement - previous state has to be truthy.
Same as changed
with additional requirement - previous state has to be falsy.
Creates condition detector that checks if next state is equal expected next state.
Example:
import { composeIf, isEqual, changedAndTruthy } from "redux-detector";
import { getUserRole, getUserId } from "./userSelector";
import { fetchAdminPermissions } from "./userAction";
export const fetchUserDetector = composeIf(
composeAnd(isEqual(getUserRole, "ROLE_ADMIN"), changedAndTruthy(getUserId)),
() => fetchAdminPermissions()
);
Creates condition detector that checks if next state is truthy.
Example:
import { composeIf, isTruthy, changedAndTruthy } from "redux-detector";
import { isAdmin, getUserId } from "./userSelector";
import { fetchAdminPermissions } from "./userAction";
export const fetchUserDetector = composeIf(
composeAnd(isTruthy(isAdmin), changedAndTruthy(getUserId)),
() => fetchAdminPermissions()
);
Creates condition detector that checks if next state is falsy.