Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is using Redux with Next.js an anti-pattern?

I'm building a Next.js app and it currently is using Redux. As I am building it I am wondering if the use of Redux is really necessary and if its use is actually an anti-pattern. Here is my reasoning:

In order to properly initialize the Redux Store in Next.js, you must create a custom App component with a getInitialProps method. By doing this you are disabling the Automatic Static Optimization that Next.js provides.

By contrast, if I were to include Redux on the client-side, only after the App has mounted, then the Redux store will reset after every server-side navigation. For instance, I have a Next.js app that initializes the Redux store on the client-side, but when routing to a dynamic route such as pages/projects/[id], the page is server-side rendered, and I have to re-fetch any information that was in the store.

My questions are:

  1. What are the benefits of a Redux store in this circumstance?
  2. Should I initialize the store in the root App component and forego the Automatic Static Optimization?
  3. Is there a better way to do to manage state in Next.js 9.3 with getStaticProps and the other data fetching methods
  4. Am I missing something?
like image 692
Jamie S Avatar asked Mar 10 '20 21:03

Jamie S


People also ask

Is it good to use Redux with Nextjs?

Redux is one of the most popular state management solutions in the React ecosystem. Nowadays, there are plenty of alternatives, but Redux is still the most trusted and widely used tool. For this reason, many projects that use Next. js want to take advantage of Redux as well.

Is Redux an anti pattern?

Bookmark this question. Show activity on this post. While learning about Redux, the God-object pattern(or anti-pattern) came to my mind- both have a single big object holding all the app data and methods to manipulate them.


2 Answers

If you have a custom App with getInitialProps then the Automatic Static Optimization that Next.js provides will be disabled for all pages.

True, if you follow this approach.

Is there a better way ?

Yes, you can create a Redux Provider as a wrapper and wrap the component you need, the redux context will be automatically initialized and provided within that component.

Example:

const IndexPage = () => {   // Implementation   const dispatch = useDispatch()   // ...   // ...   return <Something />; }  IndexPage.getInitialProps = ({ reduxStore }) => {   // Implementation   const { dispatch } = reduxStore;   // ...   // ... }  export default withRedux(IndexPage) 

You have now the possibility to use Redux only for the pages which need state management without disabling the optimization for the entire App.

Answering you question "Is using Redux with Next.js an anti-pattern?"

No, but it needs to be used properly.

More info on how is done here: https://github.com/vercel/next.js/tree/canary/examples/with-redux

I hope this helps

like image 131
ddon-90 Avatar answered Oct 09 '22 15:10

ddon-90


we use Redux mainly for 2 reasons.

1- pass data between components.

if you do not use redux, then you need to do prop drilling. To decide if user logged in or not, we fetch the data and then store it in redux store and then Header components connects to the store and gets the authentication info. If you are not using redux, then you need to fetch the user in each page and then pass it to the Header component.

Next.js pre-renders every page. This means that Next.js generates HTML for each page in advance, instead of having it all done by client-side JavaScript. Pre-rendering can result in better performance and SEO. next-redux-wrapper package allows you to use the redux with automatic-static-optimization. If you click on the link, there is a note saying: "Next.js provides generic getInitialProps when using class MyApp extends App which will be picked up by wrapper, so you must not extend App as you'll be opted out of Automatic Static Optimization:". I set up this package for my project and it is easy to setup.

But downside of using redux, it is not caching. You store the data and then you refetch it periodically to make sure it is up to date. and this is an extra expensive work. To achieve caching in redux, we use reselect library. This means extra dependency for your project on top of redux and will make you write more code.

There is a nice package swr which is created by next.js. Stale-While-Revalidate. it first returns the data from cache(stale), then sends the fetch request, and finally comes with the updated data again. I choose the use this in each page.

import useSWR from "swr";  export const useGetUser = () => {      // fetcher can be any asynchronous function which returns the data. useSwr will pass "/api/v1/me" to fetcher      const { data, error, ...rest } = useSWR("/api/v1/me", fetcher);      // !data && !error if both true, loading:true, data=null=>!data=true, error=null => !error=true      return { data, error, loading: !data && !error, ...rest };    }; 

here is resuable fetcher

export const fetcher = (url: string) =>   fetch(url).then(     async (res: Response): Promise<any> => {       const result = await res.json();        if (res.status !== 200) {         return Promise.reject(result);       } else {         return result;       }     }   ); 

2- Making api requests.

I set up redux store for my project and it was conflicting with the text-editor that I set up. Redux was somehow blocking the editor and i could not populate the store with the text that i wrote on the editor. So I used reusable hooks for fetching api. it looks intimating in the beginning but if you analyze it, it will make sense.

export function useApiHandler(apiCall) {   // fetching might have one those 3 states. you get error, you fetch the data, and you start with the loading state   const [reqState, setReqState] = useState({     error:null,     data:null,     loading:true, // initially we are loading    });   const handler = async (...data) => {     setReqState({ error: null, data: null, loading: true });     try {       // apiCall is a separate function to fetch the data       const res = await apiCall(...data);       setReqState({ error: null, data: res.data, loading: false });       alert(res.data);// just to check it        return res.data;     } catch (e) {       // short circuting in or. if first expression is true, we dont evaluate the second.       // short circuting in and. if first expression is true, result is the second expression       const message =         (e.response && e.response.data) || "Ooops, something went wrong...";       setReqState({ error: message, data: null, loading: false });       return Promise.reject(message);     }   };    return [handler, { ...reqState }]; } 

A simple apiCall function

  const createBlog = (data) => axios.post("/api/v1/blogs", data); 

and then this is how we use it :

  export const useCreateBlog = () => useApiHandler(createBlog); 

Setting redux is easy since it is easy people are not worried about the performance of their app, they just set it up. In my opinion, if you have a large app you need to set up redux or if you are familiar with graphql you can use Apollo. Here is a good article to get an idea about using apollo as state management. apollo as state management. I built a large ecommerce website and I used redux, my in my new app, since it is relatively small I do not use next js and make it more complicated.

like image 25
Yilmaz Avatar answered Oct 09 '22 14:10

Yilmaz