Using Redux Saga with Next.js

Victor Chan
3 min readJul 29, 2018

Redux is a popular state management library to use with React app. It provides a single store to store all of the application data. All components listen to one store to update their layouts instead of passing data up & down the component tree.

Redux is convenient to use with client side React app. But when it comes to SSR (Server Side Rendering) React such as Next.js, it requires some more configurations to make them work together.

Redux Saga is a redux library to handle side effects (asynchronous data flow, api fetching…etc). It makes sure the business logic is separated from the layout part to make cleaner and easier-to-test code.

However I had encountered some issues when trying to make Redux Saga working with Next.js. In here I will share my own implementation to make redux saga work in my use case.

The Pain Point

In Next.js examples, it has an example project of redux-saga using next-redux-wrapper and next-redux-saga. It seems working fine but it got one problem.

In getInitialProps() function, when using redux-saga following Next.js example. It has no way to retrieve the async callback within the function. store.getState() will always show the initial state. Although it is not ideal practise to use callback in redux pattern, in getInitialProps() we may want to have some custom logic based on the result of saga task and isServer boolean (such as server/client side redirect when session timeout). After studying the code in next-redux-saga package I decided to do my own implementation.

I have put an example project onto Github. Which is an example fetching NASA Astronomy Picture of the Day (APOD).

https://github.com/victor36max/next-saga-example

My Solution

Redux Saga has an END action to stop all the saga watchers, and an async saga.done function to wait for all current saga tasks to complete. By combining these two functions we can achieve async callback of saga tasks. So that we can have a store.js like this.

The main function to use is store.execSagaTasks(isServer, tasks), it will

  1. Run all saga watchers if not running
  2. Dispatch saga tasks in the block
  3. Stop the watchers and wait for the tasks to complete
  4. Re-run all saga watchers when it is client side

When using it in getInitialProps() , we can then get the updated state within the function.

Please go to the example project to see the complete implementation.

Please let me know in the response if any comment or better solution :)

--

--