Run a Redux Saga from a React hook without creating a Redux store. Based on an idea by @Andarist.
npm install use-react-saga redux-sagaOther package managers:
yarn add use-react-saga redux-saga
pnpm add use-react-saga redux-saga
bun add use-react-saga redux-sagaimport * as React from "react";
import { call, delay, put, select, takeLatest } from "redux-saga/effects";
import { useReactSaga } from "use-react-saga";
function* incrementAsync() {
const previousState = yield select();
yield call(console.log, "Starting from", previousState);
yield delay(2000);
yield put({ type: "INCREMENT" });
const state = yield select();
yield call(console.log, "Finished at", state);
}
function* saga() {
yield takeLatest("INCREMENT_ASYNC", incrementAsync);
}
export function Example() {
const [state, dispatch] = React.useReducer((state, action) => {
switch (action.type) {
case "INCREMENT":
return state + 1;
default:
return state;
}
}, 0);
const send = useReactSaga({ state, dispatch, saga });
return (
<div>
<p>Clicked {state} times!</p>
<button type="button" onClick={() => send({ type: "INCREMENT_ASYNC" })}>
Increment async
</button>
</div>
);
}TypeScript declarations are included with the package.
Returns a stable function for sending actions to both the reducer and the saga
channel. After a Saga put, a following select waits until React has processed
the state update.
The current React state exposed to Redux Saga select effects.
The React reducer dispatch function used for Saga put effects.
The root saga to run while the component is mounted. The saga starts when the hook mounts and is cancelled when it unmounts. Pass a stable saga function; replacing it does not restart the running task.
- React 16.8 or newer
- Redux Saga 1.5 or newer
- An ESM-compatible runtime or bundler
React and Redux Saga are peer dependencies.
Run the test suite:
bun run testInspect the package contents before publishing:
bun pm pack --dry-run