0

When I make a component that relies on something like the currently chosen language for example, or maybe a special query function to fetch data, and I provide either of these things via a ContextProvider and I make use of them with useContext(), does this not create a hidden dependency? Essentially a dependency on a sort of global-ish variable?

When defining properties on the function of a functional component, if I am missing arguments/properties when writing my TSX/typescript I will get a warning, because the function's contract/interface/signature is defined and can be statically analyzed and checked.

So, am I wrong to say that this can't be done at all with contexts? If someone were to reuse the components and the documentation did not announce the dependency it could be an issue, no? Can one use the context API and still have some sort of static dependency checking, or must one use component props / functional args to ensure dependencies are met?

If the context API does hide dependencies, why do people use it?

Addendum:

I thought all of this was relatively clear, but I will clarify that ultimately I am asking whether when importing and using a component that depends on context, if it is somehow apparent in any IDE what context it requires, without looking into its internal code or reading documentation, before runtime.

4
  • "Does the react context API not hide dependencies?" - No, not really. If the context value isn't provided then context consumers will have an issue that is rather visible and obvious, no? To be quite honest I don't quite follow what you are trying to ask here or what specific problem you are trying to solve. Can you edit to clarify what specific concern you have with using the React Context API? Commented Jun 28 at 6:02
  • Agreed this question should be edited to focus on one question. Are you asking if the interface of a context can be statically checked with Typescript? If so, the answer is yes-- we do it every day in our codebase. Commented Jun 29 at 11:26
  • Both of your comments seem to oppose the answer. Please respond to the answer by kca if you disagree with it. "rather visible and obvious, no?" - Where and when will it be visible, aside from after compiling and throwing an error because the required context is missing? Commented Jul 3 at 18:44
  • "interface of a context can be statically checked with Typescript?" - I'm asking if when using a component that uses context, if it is somehow apparent without looking into its internal code, that it uses context. Commented Jul 3 at 18:46

1 Answer 1

1

Yes, you are right, React context dependencies can't be checked at compile time.

If somebody uses your component (which uses useContext) without an appropriate provider higher in the tree, it will fail at runtime (not compile time).

The context is stored in the component tree managed by React, which is created dynamically at runtime.

Runtime dependencies aren't unique to React:

  • Think of a function that loads e.g. a config.ini file. The compiler can not check if that file will exist when the program is run by a user.

  • Or if a function relies on e.g. a document.getElementById("my-container"), somebody could try to use that function without also adding a e.g. <div id="my-container">.

The function must handle such cases gracefully.

A common way to inform a developer who uses your component about this dependency is to wrap it into a separate custom hook (which is a good idea anyway), and log or throw an error, like this:

export const useMySharedState = function(): TMySharedState {
    const context = useContext( mySharedContext );

    if( context === undefined ){
        throw new Error(
            'useMySharedState must be used within a MySharedStateProvider'
        );
    }

    return context || initialState;
};

Why do people use it?

You would use React context at a point where you wouldn't find an answer to the question "what else could I use" ?

So if you are fine with what you have without React context, then stay with it. But localization is a common use case for using React context.

Some reasons to use React context are described on passing-data-deeply-with-context. You might be interested in the section before-you-use-context and following.)

One situation where you can hardly avoid using React context is when you need some state tied to the currently rendered DOM tree, and not e.g. a global variable. This becomes especially critical when server side rendering is involved, e.g. you don't want a server side global variable that is shared between all users.

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you for very complete and clear answer. I'm glad you understood my question before I made the addendum in response to the comments about its lack of clarity.
Thanks, happy to hear that :) Yeah, I think it's just what it is. Even powerful IDEs don't check that. I just thought about what popular npm packages would do, and React Redux or React Query came to my mind, and there you just have to read the documentation, and they throw an error at runtime if the provider was missing. But for me a good error message feels safe enough, because, of course, you would always try at least once if a new component actually works.
"it will fail at runtime" - it doesn't have to. It may as well return some default value, which is in fact what useContext does itself. Of course a custom hook can then decide to fail instead of doing something still-useful, like your useMySharedState does - at least with an appropriate error message, not by ignoring that the default value was undefined.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.