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:
App
component and forego the Automatic Static Optimization?getStaticProps
and the other data fetching methods 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.
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.
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
we use Redux mainly for 2 reasons.
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; } } );
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With