Okay so, context, I’ve come across this video last night. It’s a short comparison between React and Svelte. Point 9 - Shared state (6:20) mentions that React doesn’t really have a primitive way to share state between nested components and that you basically need to use something like Redux to get that working.

But… I’ve been sharing state between nested Components in just React for a while now and didn’t know that I can’t?? But I also don’t remember where I learned to do it, so the chances are high that I just hallucinated up this method as a Junior.

Basically, when I want to share state I just make a new Context and ContextProvider, wrap it around the highest level Component I need it in, and use it lower down in the component tree.
If I need a state, I put the two outputs of the useState hook into the context (which feels nice because when I look through the code, I can see right away which children only read the value in the state and which children actually take the setter and have the capacity to change that state). Sometimes I don’t even hand out the actual setter from the state, but a new function that also does some input validation before calling the setState itself. Doing it this way has always felt pretty clean to me.

From the React documentation, it seems to me like that’s exactly how you’re supposed to use Context. But I’ve also never seen anyone else do it like that. So is it incredibly ill advised and I’ve been shooting myself in the foot this whole time?

As a more specific example, my most common use case is that I need to render fetched data in a grid. This data can be filtered, but the component that sets the filter state is either on the same level as the grid (the grid’s built in filter menu) or above it (a button that sets a predefined quick filter) or even further above that (a useEffect that looks for query parameters in the URL and sets those before the data is fetched for the first time).
So what I’d do is const [filterModel, setFilterModel] =useState() at the highest level and pass it to <FilterContext value={{filterModel, setFilterModel}}>. Then, I’d just use const {setFilterModel} = useContext(FilterContext) within all the components that write the filter and const {filterModel} = useContext(FilterContext) everywhere where I just need to read the filter, like in the hook that actually fetches my data. Does that make sense? Is there an easier/safer way to do it that doesn’t involve adopting yet another external library?

  • BlackEco@lemmy.blackeco.com
    link
    fedilink
    English
    arrow-up
    10
    ·
    edit-2
    5 days ago

    Using Context is fine, but you have to keep in mind that if any state in a Context is updated, all components that uses that Context will re-render, even if they don’t use the state that has been updated.

    Redux and Zustand allow to subscribe only to the values you need, reducing the amount of re-renders. There are also library-free alternatives like this one from romgrk.

    • python@lemmy.worldOP
      link
      fedilink
      arrow-up
      9
      ·
      5 days ago

      Oh shoot, I did not know that! :0
      That means I should keep Contexts small and all values related to another, instead of having “Page Contexts” that just store all things I need in any child. Good to know!

    • python@lemmy.worldOP
      link
      fedilink
      arrow-up
      7
      ·
      5 days ago

      Neat, thanks! I do use useContext, as far as I know the previous way to do it was to wrap children in a specific Context Consumer tag? Never quite understood the syntax of the old method haha

  • python@lemmy.worldOP
    link
    fedilink
    arrow-up
    8
    arrow-down
    1
    ·
    5 days ago

    PS: Hope this is the right place to ask! I don’t have a Stackoverflow account, and it’s not like I have actual problems with this method either. I’d just like to know if there’s problems with it that I don’t know about 😆
    I used to mainly develop in Delphi before my company said “You’re doing React now, congrats!” and just sent me and other non-React developers off to build a whole new codebase by ourselves. Very interesting project and lots of lessons learned, but to this day there still are very few people at my company that actually know React, and even fewer people that know HTML. So there isn’t really anyone who’d see the code and could say “Oh, don’t do it like that”. But that way I also don’t really learn best practices, which is why I try to ask around 🫣

  • ultimate_worrier@lemmy.dbzer0.com
    link
    fedilink
    arrow-up
    6
    ·
    edit-2
    5 days ago

    Learn about true Functional Reactive Programming and you’ll find that React breaks many of the guidelines/rules that the authors of FRP put forth. Take that observation for what it’s worth.

    IMO, there is no one right way… but a functional (stateless/immutable) core with a functional reactive or imperative shell has been shown to eliminate whole classes of errors, make refactoring less painful, and makes dealing with state a lot more intuitive and easy to reason about.

    https://youtu.be/rfmkzp76M4M

    • PokerChips@programming.dev
      link
      fedilink
      arrow-up
      1
      ·
      edit-2
      4 days ago

      Does Leptos pass the FRP guidelines? Seems like a pretty good language and I’ve dabbled in it a couple times but not yet created anything serious in it yet.

      It appears to take after React which I fear… or does it pave it’s own way?

      EDIT: Want to add that I know it takes after react but not sure if it follows the guidelines in continuous development.

      • ultimate_worrier@lemmy.dbzer0.com
        link
        fedilink
        arrow-up
        2
        ·
        edit-2
        5 days ago

        I’m not sure. Probably not.

        There are very few that pass the continuous time FRP test (according to Conal). The only ones I’ve found that keep that ideological purity are (mostly) Halogen (or Deku) in the Purescript ecosystem and reactive banana in the Haskell ecosystem.

  • abbadon420@sh.itjust.works
    link
    fedilink
    arrow-up
    6
    ·
    edit-2
    5 days ago

    Your context solution seems fine to me, if you use that value in multiple places. If you only use a context in a child, than I would just pass the value and the setter as a parameter to that child. Definitely not all shared state has to have a context around it.

    • python@lemmy.worldOP
      link
      fedilink
      arrow-up
      5
      ·
      5 days ago

      Okay nice, thank you!
      Yeah, I use the value in a lot of deeply nested places, and it usually isn’t even just one value, but a set of filterModel, sortModel and paginationModel that are always used together but need their separate states. Directly passing those through parameters even just one or two levels down really messes with the readability the code. But yeah, if it’s just one-off states only used in one child I do pass them as regular parameters :)

  • Pencilnoob@lemmy.world
    link
    fedilink
    English
    arrow-up
    4
    ·
    5 days ago

    React has changed a lot with the addition of contexts but that’s the modern way to handle it without using some kind of state management.

    I think most state management libraries are far more expensive to use than people realize. Contexts are pretty straightforward and Just Work so I’d keep using them unless you have a very good reason to switch.