This is the real purpose for react context

Sdílet
Vložit
  • čas přidán 29. 12. 2023
  • 📘 T3 Stack Tutorial: 1017897100294.gumroad.com/l/j...
    🤖 SaaS I'm Building: www.icongeneratorai.com/
    ▶️ Generate Chapters: ytchaptersgenerator.com/
    💬 Discord: / discord
    🔔 Newsletter: newsletter.webdevcody.com/
    📁 GitHub: github.com/webdevcody
    📺 Twitch: / webdevcody
    🤖 Website: webdevcody.com
    🐦 Twitter: / webdevcody

Komentáře • 71

  • @amir-ziaei
    @amir-ziaei Před 7 měsíci +47

    A better way is to just let the http call happen during the test but instead return a mocked response at network level. MSW makes this very easy. Not only you get more confidence (because your fetching logic also gets tested), but also doesn't make your code more verbose and sacrifice the runtime performance because of additional wrappers.

  • @gavinlindridge
    @gavinlindridge Před 7 měsíci +5

    You have an awesome habit of crearing just the right content at the tight time for me 👍
    Been switching my current employers codebases to use a similar pattern and this has validated i wasnt going off piest.

  • @moosa3956
    @moosa3956 Před 7 měsíci +4

    I was super confused until you showed the test implementation and then everything clicked
    Nice

  • @eduardstefan6833
    @eduardstefan6833 Před 7 měsíci +19

    Great video. As someone who has never done proper tests I always assumed that providers would be harder to test but it's actually even easier.
    Also a small tip for everyone: You can throw Error if value is null inside the useDataMuseApiContext before returning so that you don't need to always check for null in every component where you're calling the hook.
    export function useDataMuseApiContext(){
    const value = useContext(DataMuseApiContext)
    if (!value) throw new Error('You forgot to pass a value to the provider or you're using the context outside of DataMuseApiProvider')
    return value //

    • @rand0mtv660
      @rand0mtv660 Před 7 měsíci

      Yeah, creating a custom hook for every custom provider you have is an awesome pattern. I use it all the time because I just want to get the thing I'm after, I don't care if the underlying implementation is React Context or anything else. I just want to use for example "useCurrentUser()" and not worry about where this user is coming from.

    • @WebDevCody
      @WebDevCody  Před 7 měsíci +1

      Very cool! I’ve seen that in a couple of libraries but I’ve never looked into it 😅

    • @pedhead
      @pedhead Před 7 měsíci

      This is helpful if your teammates forget to wrap acomponent in a provider. Also makes it easier to change the context, all components can use the same custom hook. @@WebDevCody
      ```
      import { useMediaQuery } from "@mui/material"
      import { useEffect, useState, createContext } from "react"
      const ModeContext = createContext()
      const ModeProvider = ({ children }) => {
      const prefersDarkMode = useMediaQuery("(prefers-color-scheme: dark)")
      const [mode, setMode] = useState(prefersDarkMode ? "dark" : "light")
      const [mounted, setMounted] = useState(false)
      useEffect(() => {
      setMode(prefersDarkMode ? "dark" : "light")
      setMounted(true)
      }, [prefersDarkMode])
      const toggleMode = () => {
      setMode(mode === "dark" ? "light" : "dark")
      }
      const value = {
      mode,
      toggleMode,
      }
      return (

      {mounted && children}

      )
      }
      function useModeContext(){
      const modeContext = useContext(ModeContext)
      if(modeContext === undefined){
      throw new Error("mode context must be called within a ModeContextProvider")
      }
      return modeContext
      }
      export { ModeProvider, useModeContext}
      ```
      An added benefit is you don't need to export the entire context anymore. Also abstracts away the implementation details in your components!

    • @gavinlindridge
      @gavinlindridge Před 7 měsíci +1

      Yep love using this pattern 👍

  • @isaackoz
    @isaackoz Před 7 měsíci +4

    The best part about this is you only have to define the types once. With prop drilling you either have to define them in each file or import them, but with context TS would infer them automatically.

  • @ProfessorThock
    @ProfessorThock Před 7 měsíci +2

    Yeah this is exactly what I use context for it’s great. You can create a theme context, an api context (maybe several), a state context, etc. Very useful

  • @andreas.111
    @andreas.111 Před 7 měsíci

    This definitely helped me understand context a lot more than just keeping track of state, really useful!

  • @ltsSmitty
    @ltsSmitty Před 7 měsíci +1

    Great example. I've never really known how this was implemented so that's great to see

  • @richardantao3249
    @richardantao3249 Před 7 měsíci +9

    The same can be achieved with props. I think having multiple contexts for stubbing would be just as messy as prop drilling

  • @chiubaca
    @chiubaca Před 7 měsíci +1

    Nice advice for if you're working with storybook too!

  • @qasimqadrii
    @qasimqadrii Před 6 měsíci

    Love the way you explain! ♥

  • @m_yoda
    @m_yoda Před 7 měsíci +1

    Nest.JS forces to use the approach of dependencies injections and it is very comfortable. You don't need to mock "import" but you can just define what you need and pass to modules.

  • @nhwhn
    @nhwhn Před 7 měsíci

    Happy new year.

  • @alirezvani9149
    @alirezvani9149 Před 7 měsíci +3

    I wish they add a cleaner look for context api, something more elegant like redux api. I really hate wrapping the root element 20 times to add the contexts I want

    • @N8X4TE
      @N8X4TE Před 7 měsíci

      What is wrong with wrapping root element 20 times with providers?

    • @alirezvani9149
      @alirezvani9149 Před 7 měsíci

      ​@@N8X4TEIt gets hard to maintain real quick

    • @carljung4733
      @carljung4733 Před 7 měsíci +4

      Create a Providers component with all your providers and pass root elements as children, cleans up root file.

  • @SeibertSwirl
    @SeibertSwirl Před 7 měsíci

    Good job love!

  • @pintae8681
    @pintae8681 Před 7 měsíci

    Great content!

  • @rafavieceli
    @rafavieceli Před 6 měsíci

    And you can nest the same provider, I solved a problem where I had projects and subprojects with different permissions, so project had its contexts, and each subproject (as a child) has its own context as well.

  • @eleah2665
    @eleah2665 Před 7 měsíci

    Very good. Thanks.

  • @omarcodes5181
    @omarcodes5181 Před 7 měsíci

    Great video

  • @jacobhuiet4217
    @jacobhuiet4217 Před 6 měsíci +1

    Interesting idea. I can’t tell if I like it yet but my intuition is telling me to avoid for some reason

  • @javierperezmarin6039
    @javierperezmarin6039 Před 7 měsíci +1

    I use this exacly but with react query

  • @ankitpradhan4183
    @ankitpradhan4183 Před 7 měsíci +2

    well even passing props or argument is a kind of dependency injection.
    you cant say"real purpose". It would be the same purpose as of props i.e. to inject some dependency to component.
    The use of context is to have stuffs that essentially needs to be shared among all the sibling component. Thats it. Dont try to complicate things by bringing in words like DI.
    Even Functions are DI. some functions that are hard to be tested can be extracted out of hook or component passing dependencies and test it.
    anything you want to share among siblings like some sidebar state as example, modal providers, api calls etc etc etc.
    I will give you props to show one of most realistic example to use this.
    But beginners, be careful to properly memoize your context values because it can cause your whole shit to re render if not done properly😢

    • @ProfessorThock
      @ProfessorThock Před 7 měsíci

      I like that he’s showing off the context api because way too many people do prop drilling or jump all the way to redux and stuff when they can easily make their own bespoke lightweight contexts very easily.
      But yeah when he said it’s dependency injection I immediately was like “wait what… props are also dependency injection” which made it sound like he was just trying to use a complicated word that he didn’t know but tbf I think it is more decoupled than props so I can see what he was thinking and seems like he just quickly threw together a video to show this off

  • @jacobhuiet4217
    @jacobhuiet4217 Před 6 měsíci

    From my understanding, this would move all fetches to the client side right? At that point you lose the ability to do fetching on the server with this paradigm. If this was to be used at the top level you’d probably be better off using tanstack query to get all the other benefits of that (loading states, error handling, caching)

  • @user-ik7rp8qz5g
    @user-ik7rp8qz5g Před 7 měsíci +1

    I watched it twice, but I stop understanding from the moment you create context provider. Is there easier explanation of what we are trying to achieve by doing this and how/why exactly it is better than not doing it?

    • @WebDevCody
      @WebDevCody  Před 7 měsíci

      It’s basically a global store for dependencies that all your react components can load in when needed

    • @hypeerj
      @hypeerj Před 7 měsíci +1

      Imagine you are trying to test this component. Without Dependency Injection or intercepting the API call the test case would try to fetch you API which is something you really don't want to do. Instead, via Dependency Injection you can replace the real fetching with returning mocked response

    • @user-ri1vc4qv8j
      @user-ri1vc4qv8j Před 6 měsíci

      ​@@hypeerjgreat explanation!

    • @hypeerj
      @hypeerj Před 6 měsíci

      @@user-ri1vc4qv8j somehow I forgot about mocking functions ;b, so this is 3rd option

  • @code-island
    @code-island Před 6 měsíci

    Really good content

  • @anilsonix
    @anilsonix Před 7 měsíci

    Could you make a video react project structure like feature slice design

  • @didier2839
    @didier2839 Před 7 měsíci

    This is good💥

  • @JH-bb8in
    @JH-bb8in Před 7 měsíci +2

    Yeah but if you do this, won't you have to wrap your app.js with a whole bunch of nested providers?

    • @yousefkhalil7540
      @yousefkhalil7540 Před 7 měsíci +1

      You could use one context provider at the root where you inject an instance of every class, than you have custom hook that extracts only the class instance you really need. You could also use multiple contexts at different part of your app, each context provides a specific class instances.

    • @veedjohnson
      @veedjohnson Před 7 měsíci

      @@yousefkhalil7540do you have a codebase that shows this?

    • @N8X4TE
      @N8X4TE Před 7 měsíci

      What is wrong with the whole bunch of nested providers?

    • @veedjohnson
      @veedjohnson Před 7 měsíci

      @@N8X4TE ugly looking code, sometimes you might have to rearrange your nesting a couple of times

    • @doc8527
      @doc8527 Před 7 měsíci

      ​@@yousefkhalil7540 be aware of that if you only need a function from particular provider or instance, you will load the entire chunk of codes for a single function, which could unnecessary bloat your bundle size comparing to the import individually. One is minor, but if every single package is written in this way. It will be quickly bloated. Tree shaking might not work in this case as its inside the class. There is tradeoff and side effect if the instance modify something unexpectedly. But the side effect could be a feature and very handy if you want to modify some internal functionality during the runtime. The auto interface hinting is also very handy as a whole.

  • @fitzsimonsdev
    @fitzsimonsdev Před 7 měsíci +3

    I once tried to explain this at a job where I was contracting. They refused to believe you could do this even though I literally showed them.
    Happily I'm somewhere better now.

  • @favanzzo
    @favanzzo Před 7 měsíci

    vscode theme?

  • @ayoubkassi4103
    @ayoubkassi4103 Před 7 měsíci

    Cool video

  • @edxmo2921
    @edxmo2921 Před 6 měsíci

    Isn't It a kind of strategy pattern? Wyt?

  • @AdityaSharma-lb9bx
    @AdityaSharma-lb9bx Před 7 měsíci

    Didn't understand much. I'll watch it again

  • @therealsharat
    @therealsharat Před 6 měsíci

    I am not sure if making the layouts page a client component is a good practice

    • @WebDevCody
      @WebDevCody  Před 6 měsíci

      Is that what you got from this video?

    • @therealsharat
      @therealsharat Před 6 měsíci

      @@WebDevCody not at all, the video gave a nice use case of context, I just personally prefer setting contexts in completely different files rather than in layout
      Just so that the new viewers who watch this channel don't get the wrong idea on how to use context

    • @WebDevCody
      @WebDevCody  Před 6 měsíci +1

      @@therealsharat usually I make a separate file called providers and I use client at the top of that file.

  • @kevinclark1783
    @kevinclark1783 Před 6 měsíci

    Eh, it’s great till you have a ton of stuff on the context to mock. To me, a simple custom hook is the best, because it’s simple to mock with Jest spies and you can give each test a resolved value easily. But a nice explanation, thank you.

    • @jacobhuiet4217
      @jacobhuiet4217 Před 6 měsíci +1

      You could have a default object for mocking that mirrors what the type was and then override for your use case 🤔. I’m not sure it’s a good idea, I’m still trying to figure out if I like what he proposed

  • @guitar2935
    @guitar2935 Před 6 měsíci

    Maybe I'm just too green on React and not seeing where I could apply this but this specific example feels overly verbose. If the problem is easily swapping dependencies for testing purposes it would make more sense to me to just have a separate custom hook for testing than wrapping everything in a bunch of providers. Regardless this was a great rundown of what you can achieve with context!

    • @WebDevCody
      @WebDevCody  Před 6 měsíci +1

      A custom hook would work ok, but I’m not a fan of having your entire test suite coupled to jest spy. Because in 3 years when jest is no longer cool and something faster such as vitest comes out, now you have to refactor a ton of code to switch compared to doing the dependency injection with your own approach.

  • @claus4tw
    @claus4tw Před 6 měsíci

    I don’t know. You really should not test the fetch. Test the function That mutates the response

  • @im7254
    @im7254 Před 7 měsíci

    class lol

  • @parlor3115
    @parlor3115 Před 7 měsíci

    Idk about DI. DI automatically provides dependencies based on parameter types and supports recursive dependency resolution. Context is just global storage. Agreed on the benefits, though.

    • @WebDevCody
      @WebDevCody  Před 7 měsíci

      There are many types of dependency injection approaches. Having it be automatic isn’t the reason it’s dependency injection. Google “what types of dependency injection are there”

    • @parlor3115
      @parlor3115 Před 7 měsíci

      @@WebDevCody On a further read, this is indeed DI. Automatic injection and recursive resolution are not necessary for it to be considered so. I guess I'm used to C# and Symfony working that way.

  • @noahginsburg6140
    @noahginsburg6140 Před 4 měsíci

    second watch on this video. great content.

  • @markup100
    @markup100 Před 6 měsíci +4

    Not the best example. It feels like a backend/mobile dev is trying to teach you frontend development. Things can be much different on this side. Keep in mind about overhead you are adding by creating contexts (performance, when you update state your whole tree is rerendered, doesn't work with RSC, etc.), and you have to have a very, very good reason for using them

  • @moodyhamoudi
    @moodyhamoudi Před 7 měsíci +3

    not a piano vid unsubbed

  • @ayushjain7023
    @ayushjain7023 Před 7 měsíci +1

    React context is not for maintaining server states 😐 use react query instead plz, title of the video is misleading, it’s a first time I got to disagree with you

    • @WebDevCody
      @WebDevCody  Před 7 měsíci +1

      What does server states have to do with my video? The main idea was related to abstraction and dependencies. You can still use react query but pass the api interface methods into your react query calls