Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I came from a centralized store background — and honestly I'm falling in love with the decentralized data responsibilities. Between React Query (fetch batching & caching) and Jotai (decentralized state) I love that every component can just take care of itself. No more prop-drilling, everyone just declares their dependencies and takes care of their own.


It all sucks. The grass is not greener on the other side. Just wait for the usEffect hell that awaits you.


If you end up with useEffect hell, you are coding wrong. As OP said: it deduplicates and caches requests, there is no need to use useEffect.

Here is some example code, and imo it‘s really greener than anything else.

  async function getData() {
    const res = await fetch('https://api.example.com/...');
  
    if (!res.ok) {
      throw new Error('Failed to fetch data');
    }
  
    return res.json();
  }
  
  export default async function Page() {
    const data = await getData();
  
    return <main></main>;
  }


Where's the caching in this example?


Handled under the hood by Next 13. To be honest, they probably could have done something to make that a bit more obvious when looking at the code - it probably wouldn't hurt to throw in a simple 'cache' keyword or something.


This is the documentation I could find although it's not for 13 but Beta: https://beta.nextjs.org/docs/data-fetching/caching

They say there's a new `cache` function in React and they have patched `fetch` to use it by default (for GET requests).

Does this include a solution to the N+1 queries issue (container element requests a list of items, then item elements each request their details)? I see you can do pre-fetching, perhaps those can be batched.

EDIT: Found an example that uses DataLoader by "caching the cache". The src/api.ts module exports a cached DataLoader for characters, and src/components/CharacterAvatar.tsx imports and calls it during render simply like this:

  const character = await characters().load(id);
https://github.com/AndrewIngram/next-rick-morty


Ok, and how does this work when I need actual client side interactivity?


The problem is the moment you need to do complex combination and computation from multiple async sources, it's game over. It's the repeating of the history of flux -> redux back then all over again. Further more, what happens when you need to share this computation across multiple components?


For all of that: Jotai


Yes the point is that in this case the complexity is not by choice. If u have the business needs then u have to deal with them


Right, you put the complexity inside the Jotai


Separation of concerns is nice


That sounds like absolute hell to dig through once you hit N+1 queries.


Yeah, this is the kind of thing that seems elegant and convenient when the requirements are simple, but completely falls apart as soon as any complexity is involved.


This tracks for me as well. Very quickly, you start having to manage 10, 15, 20, or more places where data in a store is being manipulated from outside the store and it quickly becomes unmanageable on anything beyond a toy-sized application. It almost feels like a rite of passage to decentralize like that and then start to pull back when it becomes a nightmare to debug and maintain.


That's the purpose of the in-app request caching layer. Another way to see it is that you do have state in a separate store, it's just that you have one piece of state for each resource that can be requested. So it's not that all the components are requesting the /users resource, it's more that all the components a requesting the value of the /users store, and the /users store fetches the data once and determines whether the data is loading, present, needs to be updated, etc.


That caching layer sounds like a footgun.

RTK Query does something similar, offering multiple ways to initiate, update and use the data of the queries.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: