loading...
Cover image for Why I Stopped Using Redux

Why I Stopped Using Redux

g_abud profile image Gabriel Abud Updated on ・6 min read

Redux was a revolutionary technology in the React ecosystem. It enabled us to have a global store with immutable data and fixed the issue of prop-drilling in our component tree. For sharing immutable data across an application, it continues to be an excellent tool that scales really well.

But why do we need a global store in the first place? Are our frontend applications really that complex or are we trying to do too much with Redux?

The Problem with Single Page Applications

The advent of Single Page Applications (SPAs) such as React, brought about a lot of changes to how we develop web applications. Separating our backend from our frontend code allowed us to specialize and separate out concerns. It also introduced a lot of complexity, namely around state.

Fetching data asynchronously now meant that the data had to live in two places: the frontend and the backend. We have to think about how best to store that data globally so it's available to all of our components, while maintaining a cache of the data to reduce network latency. A big part of frontend development now becomes burdened with how to maintain our global store without suffering from state bugs, data denormalization, and stale data.

Redux is not a Cache

The main problem most of us get into when using Redux and similar state management libraries is that we treat it as a cache for our backend state. We fetch data, add it to our store with a reducer/action, and refetch it periodically to make sure it's up to date. We are making Redux do too much and using it as a catch-all solution to our problems.

One important thing to remember is that our frontend and backend state are never really in sync, at best we can create a mirage that they are. This is one of the downsides of the client-server model and why we need a cache in the first place. Caching and maintaining state in sync is immensely complex however, so we shouldn't be recreating this backend state from the ground up like Redux encourages us to.

The line between backend and frontend responsibility quickly becomes blurred when we start to recreate our database on the frontend. As frontend developers, we shouldn't need to have a thorough knowledge of tables and their relationships in order to create a simple UI. Nor should we have to know how best to normalize our data. That responsibility should fall on the people designing the tables themselves - the backend developers. Backend developers can then provide an abstraction for the frontend developers in the form of a documented API.

There are now a myriad of libraries (redux-observable, redux-saga, and redux-thunk to name a few) built around Redux to help us manage data from the backend, each adding a layer of complexity to an already boilerplate-heavy library. I believe most of these miss the mark. Sometimes we need to take a step back before taking a step forward.

What if we stop trying to manage our backend state in our frontend code and instead treat it like a cache that just needs to be updated periodically? By treating our frontends like simple display layers that read from a cache, our code becomes significantly easier to work with and more accessible to pure frontend developers. We get all of the benefits of separating out concerns without most of the downsides of building SPAs.

A Simpler Approach to Backend State

There are a couple of libraries that I believe are a huge improvement over using Redux (or similar state management library) for storing backend state.

React Query

I've been using React Query for a few months in most of my personal and work projects. It's a library with a very simple API and a couple of hooks to manage queries (fetching data) and mutations (changing data).
Since using React Query, not only am I more productive but I end up writing 10x less boilerplate code than I would have with Redux. I find it easier to focus on the UI/UX of my frontend applications without having to keep the whole backend state in my head.

To compare this library to Redux, it helps to see an example of the two methods in code. I've implemented a simple TODO list fetched from the server with both methods, using vanilla JS, React Hooks, and axios.

First, the Redux implementation:

import React, { useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import axios from 'axios';

const SET_TODOS = "SET_TODOS";

export const rootReducer = (state = { todos: [] }, action) => {
  switch (action.type) {
    case SET_TODOS:
      return { ...state, todos: action.payload };
    default:
      return state;
  }
};

export const App = () => {
  const todos = useSelector((state) => state.todos);
  const dispatch = useDispatch();

  useEffect(() => {
    const fetchPosts = async () => {
      const { data } = await axios.get("/api/todos");
      dispatch({
        type: SET_TODOS,
        payload: data}
      );
    };

    fetchPosts();
  }, []);

  return (
    <ul>{todos.length > 0 && todos.map((todo) => <li>{todo.text}</li>)}</ul>
  );
};

Note that this doesn't even begin to handle refetching, caching, and invalidation. This simply loads the data and stores it in your global store on load.

Here's the same example implemented with React Query:

import React from "react";
import { useQuery } from "react-query";
import axios from "axios";

const fetchTodos = () => {
  const { data } = axios.get("/api/todos");
  return data;
};

const App = () => {
  const { data } = useQuery("todos", fetchTodos);

  return data ? (
    <ul>{data.length > 0 && data.map((todo) => <li>{todo.text}</li>)}</ul>
  ) : null;
};

By default this examples includes data refetching, caching, and stale invalidation with pretty sensible defaults. You can set the caching configuration at the global level and then forget about it - in general it will do what you expect. For more on how this works under the hood, check out the React Query docs. There are a ton of configuration options available to you, this only begins to scratch the surface.

Anywhere you need this data, you can now use the useQuery hook with the unique key you set (in this case "todos") and the async call to use to fetch the data. As long as the function is asynchronous, the implementation doesn't matter - you could just as easily use the Fetch API instead of Axios.

For changing our backend state, React Query provides the useMutation hook.

I've also written a curated list of React Query resources that you can find here.

SWR

SWR is conceptually almost identical to React Query. React Query and SWR were developed around the same time and both influenced each other in positive ways. There is also a thorough comparison between these two libraries in the react-query docs.

Like React Query, SWR also has really readable documentation. For the most part, you can't go wrong with either library. Regardless of what ends up becoming the norm in the near future, it will be much easier to refactor from that than the equivalent Redux mess.

Apollo Client

SWR and React Query focus on REST APIs, but if you need something like this for GraphQL the leading contender is Apollo Client. You'll be pleased to learn that the syntax is almost identical to React Query.

What About Frontend State?

Once you start using one of these libraries, you will find that on the vast majority of projects, Redux is overkill. When the data fetching/caching part of your app is taken care of, there is very little global state for you to handle on the frontend. What little amount is left can be handled using Context or useContext + useReducer to make your own pseudo-Redux.

Or better yet, use React's built in state for your simple frontend state. There is nothing inherently wrong with that.

// clean, beautiful, and simple
const [state, setState] = useState();

Let's embrace the separation of backend from frontend more fully instead of remaining in this ambiguous in-between state. These up and coming libraries represent a shift in how we manage state in single page applications and are a big step in the right direction. I'm excited to see where they lead the React community.

Discussion

pic
Editor guide
Collapse
chamsddine profile image
Bouzaine Chamsddine

React-Query and context api can never replace redux (they are not the same thing ).and he is not overkill , the one time i think redux is overkill is if you are working on small projects , you can argue that we can use other state management solutions like xstate maybe but to build a scalable and maintainable application we need a centralized state .

Collapse
serhiiohorodnyk profile image
Serhii Ohorodnyk

That is very true - they are not the same things. But that is exactly the point of this article: redux is a global state management library, while react-query (or SWR) are cache management libraries. And the reality today is that most web applications (I would dare to say more than 95%) do not need global state management at scale, they need sophisticated caching library, because "single point of truth" is not in redux state - it's in the DB, coming from your api.

And I would argue about following "to build a scalable and maintainable application we need a centralized state" - I've refactored so many relatively complex react applications away from redux and they all became a lot more predictable and thus more scaleable and easier to maintain (not to mention that number of lines became 5-10 times less).

So if you have a source code example of an app that needs redux to be maintainable - I'd be happy to check it out!

Collapse
bhldev profile image
Brian Lim

Redux being "overkill" doesn't have much to do with "scale" (that's a misconception) but the requirements

medium.com/@dan_abramov/you-might-...

The man himself

If you don't need any of those requirements listed, using redux could be an exercise in technical supremacy and machoism. Or perhaps premature optimization.

There's also many other non-technical requirements for using redux that I won't speak to. For example, it makes interviewing or filtering easier. Yes redux, especially a lot of redux? You probably have enough frontend. No redux? You probably don't. If you work somewhere where everyone has a Ph.D. and skill is not an issue because everyone learned Redux in four hours then maybe everyone is excited and will use "centralized state". But if you don't, if you work somewhere with enterprise software where everyone wants to get home on time not work overtime and most important not spend hours and hours writing boilerplate (or engineering solutions to avoid boilerplate, a fraught business itself), then redux could be a curse.

Redux is intended to solve a problem if you don't have that problem you don't need it.

Collapse
captaincodeman profile image
Simon Green

I honestly think that blog post is a bit of a cop-out. The reality is that what Redux does is great, but it does it all in such a complicated way that it makes things difficult, so difficult that it may not be worth it unless you're doing a significant problem.

But you can do all that Redux does in a much simpler way so you don't have to write as much code and do it all with significantly fewer bytes (more the ecosystem of extras that you end up including than the core lib itself)

More in-depth thoughts (ranting) about Redux an an alternative I came up with:
captaincodeman.com/2020/05/31/intr...

Collapse
stephyswe profile image
Stephanie

On one router page we make 15 action based api calls . How you handle that w/o redux ?

You also have persist state in redux.

Collapse
g_abud profile image
Gabriel Abud Author

At a certain complexity it may make sense to start using Redux. I am not against Redux as a tool (I say that in the first paragraph) and I think its design is excellent, I'm more against what it encourages us to do.

Having said that you can easily do that many calls with React Query and SWR and have them be cached so they are not refetched every time. You simply use a hook in the components that are needed and don't have to worry about managing your own global store.

Thread Thread
mpocock1 profile image
Matt Pocock

I'd argue that at a low level of complexity, use useReducer, useState and useContext. At a high level of complexity, use XState/useContext. XState handles complexity much better than Redux.

Thread Thread
theodesp profile image
Theofanis Despoudis

That implies that you know how to create correct state machines...

Collapse
kravemir profile image
Miroslav Kravec

one time i think redux is overkill is if you are working on small projects ... to build a scalable and maintainable application we need a centralized state

Redux is a very wrong tool for any front-end (dumb client/interface) of information systems, where the back-end is the single source of truth - the centralized state.

Even user's settings are stored in BE, and therefore should be treated as network resource. I couldn't imagine working with information system, which wouldn't remember my settings across different sessions / browsers / computers. Rather, not have any user settings at all, then.

However, redux might be a good choice for rich applications, where the front-end is practically a full-featured desktop application, and the back-end serves as mere storage for BLOBs (with metadata).

My opinion is based on experience with a large / enterprise application using Apollo GraphQL. And, that I've just migrated my pet project from custom-crafted very-sub-optimal redux caching solution to react-query.

Collapse
farazamiruddin profile image
faraz ahmad

I agree with your statements about Redux. The problem honestly is the way it's used.

If used to only store state that is actually global, it's fine. However, I think most of the time a lot of us like to default to throwing things into the global store to avoid prop drilling.

You can simply use context these days to avoid prop drilling. We've been replacing our application at work from Redux and moving towards using useState and useReducer, along with context. It's been fantastic.

If you're interested, you can check out my pattern for React Context

Collapse
g_abud profile image
Gabriel Abud Author

I've been doing the same thing on all of my projects, moving to pure useReducer, useContext, and useState. I am sure there are legit cases for Redux but I think it's for a select few, really complex applications.

If you haven't tried react-query or similar library, I'd encourage you to try them out as well. It handles the data layer really cleanly and independently from context.

Collapse
caiangums profile image
Ilê Caian

TL;DR: If you are starting a project from scratch, consider not typing

$ yarn add redux react-redux
Enter fullscreen mode Exit fullscreen mode

Until it's necessary.

How to discover if it's necessary? For a quick discover, ask some simple questions:

  • does it have more than just one page?
  • does it have more than 1 form?
  • does it need to fetch tons of data?

If the answers are "No", consider using Context API or React-Query.

Remember: You are free to use anything you want! Be happy!
Stay home ❤️

Collapse
ug02fast profile image
Arthur Zhuk

I'm using a custom caching solution like react-query at scale pleasantly. Redux is the wrong choice.

Collapse
caiangums profile image
Ilê Caian

I would never say: Redux is the wrong choice always. Sometimes you need what it offers! Sometimes, Redux is really a big DON'T.

I'm happy that you found a perfect tool for your projects!

Thread Thread
michaelbushe profile image
michaelbushe

Redux is never the best choice. :)

Collapse
khelnagar profile image
khelnagar

If my answer is yes to all, and I am actually developing a social network like app (somehow FB like), can context API and React built-in state management suffice?

Collapse
samwightt profile image
Sam Wight

Probably not, no. The main tools that Redux provides are middleware and dev tools. With middleware, you can integrate things like thunks into your store, making it incredibly easy to fetch data in your app. Dev tools make it very easy to actually see what's going on in your store, something useReducer or useState can't let you do as easily. If you're building any sort of complex application, I'd recommend using Redux at the start to avoid the issues that pop up later if you don't.

Collapse
caiangums profile image
Ilê Caian

It depends! For big amount of data, Context API tend to be slow. Even if you want to go with Redux, consider checking MobX lib and thinking what you really need. There's no silver bullet and sometimes your thrive for using one specific tool to all your needs can drive you to unpleasant places! 😄

Thread Thread
khelnagar profile image
khelnagar

Thank you for your reply.

Sure it depends that’s why I am still thinking. I am not really aware yet of how big data would be or which parts (all or some?)of the app would need the global state so that I can define it is really big, to decide whether to dump Context/hooks.

I more inclined into avoiding Redux as I can see that my current challenges are just prop drilling and updating state globally from anywhere in comp tree, where I see built-in React is enough.

Am I missing future challenges that Redux would solve down the line, and I am not aware of as not grown big yet?

Thread Thread
caiangums profile image
Ilê Caian

You can always change from one to another tool, if you need to do so. In my personal opinion we lose too much time advocating for one or another tool instead of experiment and create Proof of Concepts.
There are things that we'll only learn by experience and time. If Context API is ok and you feel that this tool attend all your needs, it's ok to maintain! Just don't be blind to another tools and avoid learning just because someone told you to :smile;

Collapse
rad_val_ profile image
Valentin Radu

you will find that on the vast majority of projects, Redux is overkill

I've heard this statement 100 times and I have to object: it's not overkill, it's simply not the best tool for managing state in a React app for the reasons you mentioned and others as well (e.g. the extra effort/complexity/library for async operations, the extra setup for statically typed actions, etc.)
No matter if we're talking about 100 lines of code or 100,000.
On the other hand, an Apollo-based solution or a React Query one coupled with a BFF brings us closer to what should be our goal in the first place: an architecture that allows seamless state management between the server and the client.

Collapse
g_abud profile image
Gabriel Abud Author

Yeah my point is not that Redux is bad per se, more that the way we generally use it and other state management libraries is bad. If you have a lot of global state to manage that is truly frontend state, then it may be worth it to use Redux.

What I meant is that we're generally not using it correctly and it often leads to bad patterns where we end up shoving everything in a global store and recreating a cache from scratch.

Collapse
rad_val_ profile image
Valentin Radu

Got it and I agree: it's not generally bad. It's not good either tho 😅 And has never been, regardless of project size.

we end up shoving everything in a global store and recreating a cache from scratch

👍🏽 I guess, independently of whether we use Redux or not, we'll end up creating some sort of cache-like system, because in the end, that's what out client side state is in a way: a cache for the backend state. So yeah, better if we don't start from scratch every time.

Collapse
macsikora profile image
Maciej Sikora

Good article. My main issue with Redux was that no matter how I tried to make the state well architected and normalized, I have always ended with a mess. The whole normalization is a big pain in the ass which really creates more problems than it solves.

Also this common talking - don't put into Redux private component state, ends always by - nobody knows what to put to Redux, so let's put everything and we are done with this question.

I am also done with Redux, it's never worked fine. Reducers are great, but that we have in useReducer. So bye bye Redux.

Collapse
g_abud profile image
Gabriel Abud Author

Well put, this is exactly my experience too. No one is trained on how to use Redux correctly and it quickly devolves into a mess. You have to have very stringent code reviews/practices to keep it maintainable and in most situations it feels like over-engineering.

Collapse
vlence profile image
Victor Basumatary

By treating our frontends like simple display layers that read from a cache, our code becomes significantly easier to work with and more accessible to pure frontend developers.

That's literally the definition of a frontend - a dumb interface. Frontends should never do anything with data besides display it, and collect it to send it off to the backend (think forms). It's interesting how the industry went from writing web applications using technologies like PHP, which in my opinion is so much easier to do and reason about, to making websites with React, Angular, etc. and all of that just to reinvent the wheel - like state management.

State management is a non-issue if your website's HTML is generated at the server side, because that's where the database is.

Collapse
michaelbushe profile image
michaelbushe

I think there is a lot of opportunity in that "never" space. Clients, even phones, today are more powerful than servers of not long ago. Why pay google or amazon for CPU when you can get your user's CPU free and provide them a better, faster service? I'm not the only one who things so, sheck out AWS GreenGrass. docs.amazonaws.cn/en_us/greengrass...

Collapse
vlence profile image
Victor Basumatary

Sure I suppose so but in my experience allowing yourself to process data both on the frontend and the backend only introduces unnecessary problems.

I think the most glaring problem is that you need to ask yourself where data should be processed whenever there is a need to process data. Consider a website which stores timestamps in its database. More often than not you'd like to show your users a nice, clean date string instead of a timestamp. Where should that formatting happen? That is data processing too after all. Should it be done client side? Server side? Instead of dealing with that dilemma you might as well process the data where it is - the server side, the backend. In my example of timestamps I like to tell the database in the query itself how I want my date to look like.

Yes data processing requires CPU but how much CPU do you really need anyway? And we're not getting the user's CPU for free. There are lots of people who don't have powerful phones and every millisecond spent in processing data shows. If you really need that extra CPU for data processing (What are you doing anyway? Image resizing? Video compression?) then consider using queues and queue workers.

Since the original discussion is about websites we should talk about JavaScript. You need JavaScript to do data processing client side. You have no guarantee JavaScript will be available client side. Here are some reasons why:

  • User disabled JavaScript
  • JavaScript could not be downloaded
  • User agent may not support JavaScript
  • User agent may not support the version of JavaScript downloaded

And as for Greengrass, this is what the docs say:

AWS IoT Greengrass is software that extends cloud capabilities to local devices. This enables devices to collect and analyze data closer to the source of information, react autonomously to local events, and communicate securely with each other on local networks. Local devices can also communicate securely with AWS IoT Core and export IoT data to the AWS Cloud. AWS IoT Greengrass developers can use AWS Lambda functions and prebuilt connectors to create serverless applications that are deployed to devices for local execution.

I've never done IoT, let alone use Greengrass, but this to me clearly reads as a backend-frontend setup where the lambda functions are the backend and the device sensors or whatever is collecting the data is the frontend. Even here you're not doing the data processing on the frontend.

Collapse
tannerlinsley profile image
Tanner Linsley

First off, I love this article to the bone. As a point of polish, I think it's worth clarifying here that SWR did not inspire React Query. twitter.com/tannerlinsley/status/1...

Collapse
g_abud profile image
Gabriel Abud Author

Ah okay, in your old README you had a section that I thought said that. But maybe I misunderstood and you meant some of the ideas were influenced by SWR (and vise versa) . Will change it now!

Collapse
tannerlinsley profile image
g_abud profile image
Gabriel Abud Author

If you are making a SPA, you have no assurance that they are in sync though, even in this instantaneous situation. By the time you load that array someone could have edited that data in the backend already. This is important to keep in mind so you don't make any assumptions that later become very real bugs. So if you have an application where there aren't a ton of live edits, this may not matter as much, and you're right about that. But backend/frontend are never really in sync and making this assumption might lead to weird UI/UX behavior down the line, as your app grows and you get more users editing the same data.

Collapse
saluminati profile image
Salman Sohail

As a heavy back-end (mostly rails) dev who can work on front-end, it always seems redux is an overkill to me with a massive blilerolate. I will explore this option of react query which seems very simple. Thanks for sharing this with us.

Collapse
vikrantbhat profile image
Vikrant Bhat

I agree, redux can be an overkill sometimes.

Collapse
szabikr profile image
Szabi

It’s going to be 4 years soon that I found out about Redux and I used it in most of my projects since, they were all medium to large size applications. I am actually big fan of the concept and can cope with the boilerplate as well, however, it just became a bit boring to work with lately. And I’m looking forward to trying out these solutions that you’re mentioning @g_abud , especially react-query and also those common hooks.
Thanks for sharing!

Collapse
gilbertoalbino profile image
Gilberto Albino

I may be criticized here, but for simple projects I see no use of React or any similar library/framework, I prefer going with vanilla JS or jQuery.

I think most people misuse or overuse technologies.

It explains the critical bad quality of most projects actually.

Collapse
g_abud profile image
Gabriel Abud Author

I think this is fine, kind of not the point of the article but I agree. Knowing when to use technologies and when they are overkill is a big part of being a good software engineer. If you are making static websites and don't need fancy Javascript capabilities, React might be overkill.

Collapse
samkhan27 profile image
Sam Khan

Redux is not a framework or a technology. It's an architecture pattern and a damn good one at that. So much so, that facebook includes the useReducer hook in React's top level APIs.

I agree that there is a tendency in the community to use redux before it becomes necessary and to do so without understanding the benefits it provides. However, to suggest SWR and and React Query as an alternative to redux is harmful and MISLEADING. You could pair them with redux to form a pretty effective stack.

I have shipped complex production apps with and without using redux. It usually depends on the use case, app's requirements and complexity in the application's state management. I've found that in applications where redux is not a good fit, apollo client is. This is because apollo client utilizes a normalized state in to form of apollo cache. Apollo client sort of abstracts out the custom plumbing you would otherwise have to write if you were using redux and if the out of the box features in apollo client are enough for you, it may just be enough. Some of those apps still benefit from redux like patterns though, like using the useReducer hook in complex components.

Collapse
pixelgoo profile image
Anton Melnyk

Redux has nothing to do with managing backend state and if you're using it just to have global "copy" of the backend on your frontend or "caching", of course it will be just unnecessary overhead.

As well as it's not really related to the API calls in the first place. It shouldn't be compared to react-query or apollo.

Redux is architectural pattern, easier debugging and powerful middlewares like redux-saga for managing complex, really complex workflows and states.

If you use it just for data fetching, global variables or prop drilling issues, you are using wrong tool.

Collapse
g_abud profile image
Gabriel Abud Author

That's exactly my point. Once you get rid of using it for backend state, it's hardly needed for most simple applications. And I'm picking on Redux but any state management library falls into some of the same temptations. Yet everyone likes to start a project with Redux (or MobX, etc.) because it's so commonly used and referenced before they even have any real use case for it.

In the Redux docs, it has plenty of examples of using it for storing backend state (redux.js.org/recipes/structuring-r...), so I disagree with you that that was never the intention, not to mention all the libraries that have sprung up (mentioned in the article above, such as redux-saga) to deal with backend state. If it was never the intention, I would expect Redux docs to warn against this very tempting use case instead of showing you how to do it. From experience, I would say there are plenty of people using it for this reason, maybe even the majority.

Collapse
dandv profile image
Dan Dascalescu

One important thing to remember is that our frontend and backend state are never really in sync, at best we can create a mirage that they are.

Amazing how absolutely everyone who commented on this post, took the sentence above for granted.

It's just not so, if you use the right tool for the job.

If you need your frontend to be in sync with backend data, and don't want to deal with stale data, cache invalidation and all that, then use a full-stack framework like Meteor.js, that has solved this problem for good.

No, Meteor is not dead.

Yes, Meteor does scale. It scaled remarkably well even 4 years ago.

Yes, Meteor does work with MySQL.

Yes, Meteor supports PWAs.

No, Meteor is not "trendy". It's a reliable workhorse that lets you actually focus on the code that makes your app different, and not rewrite the same boilerplate (including a user accounts system taking weeks to properly write, which Meteor solves with literally one line of code).

Collapse
g_abud profile image
Gabriel Abud Author

How is that statement not true? It's how the web works, even if you have "real time apps" using websockets, by the time the data reaches you it could already be stale technically. So even if you have perfect caching you will still have this problem. As far as I know there isn't a 100% perfect solution to this, although good caching comes close.

Collapse
dandv profile image
Dan Dascalescu

Sure, that's technically true, but for the vast majority of practical intents and purposes, Meteor solves that sync problem and you don't have to write any code. There's certainly value in not reinventing a wheel that's very hard to get round, and a wide perspective of the problem would include full-stack frameworks even if they only offer a 99% solution to this.

Meteor offers more than just caching, including optimistic updates and real-time sync between all connected clients.

Thread Thread
g_abud profile image
Gabriel Abud Author

I personally haven't used Meteor but if it handles caching well, then I think I'd be in favor of using it.

I realize the title of this article kind of entices a technology flame war but that's not what my point is. It's that managing backend state yourself on the frontend, in the majority of cases, is probably not the best approach. Any technology that handles frontend caching/fetching/invalidation/mutations well is a good way forward.

Thread Thread
dandv profile image
Dan Dascalescu

Any technology that handles frontend caching/fetching/invalidation/mutations well is a good way forward.

Well put. One of those technologies is React Query, another is Apollo Client, and I bet that if you had read about Meteor, you would've included it too.

Collapse
thomasburleson profile image
Thomas Burleson

I enjoyed your article and your thoughts about the dangers/challenges on data caching. Good stuff.

Redux, however, is more than just a front-end caching mechanism.

The purpose of Redux is to (a) separate UI and business logic using event/action delegation, (b) centralize state changes code, and (c) encourage 1-way data flows.

Equally important as state management is the concept of sharing state. How to share data and push state changes is the most challenging part... one where Redux solutions fail IMO.

MobX, Recoil, and Akita are all current/upcoming solutions that address the challenge of pushing changes and notifications to data consumers (aka observers).

Check out my articles on medium.com/@thomasburlesonia; perhaps these will provide value-add to your insights.

Collapse
wangqiyang profile image
wang-qiyang

Hi, I'm the editor of InfoQ China which focuses on software development. We like your article and plan to translate it into Chinese and publish it on our website. So I want to ask for your permission first! This translation version is provided for informational purposes only, and will not be used for any commercial purpose.

In exchange, we will put the English title and link at the end of Chinese article. If our readers want to read more about this, he/she can click back to your article.

Thanks a lot, hope to get your help. Any more question, please let me know.

Collapse
g_abud profile image
Gabriel Abud Author

Yep, that's fine as long as the credit is given to the original article. Thanks!

Collapse
wangqiyang profile image
Collapse
marianban profile image
Marian Ban

The redux toolkit version is less boiler-platy:

const todosSlice = createSlice({
  name: 'todos',
  initialState: [],
  reducers: {
    setTodos: (_, todos) => todos,    
  }
})

const { setTodos } = todosSlice.actions;

export const fetchTodos = () => async (dispatch) => {
  const { data } = await axios.get("/api/todos");
  dispatch(setTodos(data));
}

export const App = () => {
  const todos = useSelector((state) => state.todos);
  const dispatch = useDispatch();

  useEffect(() => {   
    dispatch(fetchTodos());
  }, []);

  return (
    <ul>{todos.length > 0 && todos.map((todo) => <li>{todo.text}</li>)}</ul>
  );
};
Collapse
juliang profile image
Julian Garamendy

Great article! Treating data cache differently from UI or app state is key.

For anyone who hasn't tried React-Query or SWR yet, I recommend this 18-minute video tutorial by Leigh Halliday.

Also, I wrote How SWR works behind the scenes, if you're curious.

Collapse
ryanmr profile image
Ryan Rampersad

I use redux to compose multiple API calls into something that my frontends can display and for refresh-safe persistence with redux-persist. Can react-query help with data composition and that persistence?

Collapse
g_abud profile image
Gabriel Abud Author

I assume by data composition you mean creating your own, normalized store on the frontend?

This is kind of fundamentally different from how react-query and SWR work. I think these libraries discourage you from creating this normalized state yourself. Think of each API call as unique key in your global cache. You could certainly manage these yourself but then I think you lose the benefits that these libraries provide and at that point you may as well be using Redux. The normalization aspects should fall on the backend developers, and we shouldn't be totally against denormalization everywhere on the frontend anyway. Sometimes it makes more sense to send back denormalized data from the backend to avoid making N+1 queries.

As for persistence, why is that important to you? To avoid network latency? I think react-query and SWR prioritize data consistency over reducing network calls, so in general it will be easier to manage consistency. You could still store it in local storage though, it's just not provided by default. Take a look at this discussion for more if persisting is important to you: github.com/tannerlinsley/react-que...

It's possible that your application might have a very good use case for Redux, but I would encourage you to check out these other libraries especially if you find managing your Redux store to have gotten overly-complex.

Collapse
sgolovine profile image
Sunny Golovine

Since hooks and contextAPI came out I've started using Redux in other ways. While I used to fetch data in the Redux layer and pass it into state, I now use Redux with Redux Persist as a form of data storage for the user.

In a way Redux is now an API for interacting with locally stored objects and for that I found it fantastic. I found that you can quickly migrate an app from one platform (say web) to another (native) and all you have to do to adapt your data storage with redux is to pull in another persistence library that works with that platform.

Collapse
ablamunits profile image
Boris Ablamunits

This is an excellent read - thanks for posting this. I have seen multiple times developers reaching out for Redux almost automatically for their projects. It seems to be the go-to tool for state management, even though in reality Redux was designed to solve a very specific, global state management problem - which an app might not have. By the time the app has reached a certain size, it is very hard for teams to imagine a cleaner approach exists. I think part of the problem is with the resources available for newcomers to React, where tools like Redux are mentioned in every tutorial. Its important to understand the problem the tool is designed to solve, before using it.

I would be interested to know what kind of feedback you got from teams using Redux when you brought up the idea it isn't always necessary.

Collapse
latobibor profile image
András Tóth

I recommend using overmind.js - that's my go to redux alternative. It was very easy to setup, written in TypeScript handles it really well too and I could cut many lines of boilerplate with it.

By the way, I would like to hug all of you guys, I felt so alone in my criticism on redux :D . I have encountered apps where I could not tell where the hell it was fetching data, because it was FP-style redux, so everything was wrapped in another function and got a function parameter as a callback and lost of layers of indirection to make sure no-one accidentally mutates the immutable state (like how often that happens if you do code-reviews? BTW, there are libraries that guarantee the state to be immutable - I could follow all the redux best practices and yet still called a .sort() on an array without any warning). And then it was just a lame option selector that loaded one endpoint if you chose A) and another if you chose B).

Collapse
1995muzaker profile image
Shaikh Muzaker

Using rather than redux would like to prefer SWR with context api as of i didn't got chance to work on SWR but i went through docs it is much comfortable. what i feel is compare to redux SWR will be great where not need to call actions multiple time for dispatching the function. we can use a hook in the components that are needed and don't need to much worry about managing the own global store while using SWR with context api.

Collapse
robin2309 profile image
robin2309

Thanks for the article, I did not know about React-Query, it looks like a great solution. When I am trying to think about how I would use it, one question comes to my mind as to how does it replace redux :
How can I apply some transformation on the data that has been fetched by React-Query before the data is actually consumed by the component, like I currently do with selectors on my redux state ?

Collapse
spicecoder profile image
pronab pal

I don't have too much experience with Redux , but I believe fundamentally Redux is trying to address inter-component state management issue , & it is not necessarily geared towards back-end sync solution ; I agree many times Redux is not needed because to start with not many developers plan to sync multiple components as it brings another level of complexity in the App , but from re usability and modular design perspective that make sense e.g to treat shopping cart item list and total current value of items as separate components , e.g the payment module need not need to know what items are there as long the total value is correct...

Collapse
felipemillhouse profile image
Felipe Santos

I agree with you in a few things, and yes SWR and react query are awesome, I love them. The problem is even the data is on the cache, in background the library will do a new API request aways you’ll need to use some data. You are creating a problem for your backend if you remove redux. Imagine that you have a state user.name, that state you get on login. API, and you need to use on main screen, on profile, on posts and so on, how many unnecessary API calls do you gonna do just to show the user name?

Collapse
barocsi profile image
barocsi

There are always articles of why you should use "XY" and couple of months/years later why I stopped using "XY". It's not because it's useful or not, its because dev people keep jerking off over their dev tools instead of using working ones to make money.
Redux was never a good tool for anything it was just another medium to make endless articles and arguments by developers who were fucking bored to do real work and wanted to go to conferences instead.

Collapse
stereoplegic profile image
Mike Bybee

While it's heavy in bundle size (though potentially getting much smaller now that the goal is to modularize away from PouchDB while keeping its offline-first/persistence and sync paradigms), RXDB is a fantastic option not only for local state and "fetching," but to actually keep the frontend and backend state in sync. With its GraphQL replication, you don't even need to rely on the super-chatty Couch/Pouch replication protocol (in fact, Hasura just shared a how-to on using it to sync with RXDB - which allows you to use a DBaaS like e.g. AWS Aurora - via two simple GraphQL mutations for the replication stream).

The author of RXDB commented on an issue years ago that he didn't consider it a state management solution to replace the likes of Redux but, given what I just laid out above, it kinda is (and then some) in a much more manageable fashion.

Collapse
psiho profile image
Mirko Vukušić

Never even touched Redux. Started with Mobx and React at the same time. So happy. I find Mobx simple and issue both on small and larger projects