Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React JS: Find out if component is inside a context provider

Tags:

reactjs

I'm using React's Context API to pass some context to lower level components.

I want to be able to run the component without a context provider (for testing). For this to work, I need to check whether there is a context provider around my component.

Example code:

const Wrapper = () => {

  // in my real app, there are some levels 
  // between the provider and the child component

  return <NameProvider value={name: 'User'}>
    <ChildComponent />
  </NameProvider>
}

const ChildComponent = () => {
  if (/* what can I put here ? */) {
    // inside Provider
    return <NameConsumer>
      {context => <span>{context.name}</span>}
    </NameConsumer>
  } else {
    // no provider available, e.g. in a test file
    return <span>Test Text</span>
  }
}

This question is not specifically about testing. There could be other situations where a component needs to work both inside and outside a context provider.

like image 299
KWeiss Avatar asked Sep 04 '18 13:09

KWeiss


People also ask

Is context provider a component?

Context.ProviderEvery Context object comes with a Provider React component that allows consuming components to subscribe to context changes. The Provider component accepts a value prop to be passed to consuming components that are descendants of this Provider. One Provider can be connected to many consumers.

Can you use the same context provider on multiple components?

We can pass in anything we want into the value prop of the context provider component in React. So we can share anything between components as long as we pass them into the value prop.

What is Contextapi?

What is Context API? The React Context API is a way for a React app to effectively produce global variables that can be passed around. This is the alternative to "prop drilling" or moving props from grandparent to child to parent, and so on.

How do you use context in useMemo?

Memoize the Context values with useMemo The simplest way to optimize the Context is to useContext in nested components inside App. js . When Wrap the Context value inside of useMemo, all values will be memoized, and useMemo will only recompute the memoized value when one of the dependencies has changed.


1 Answers

No official way is provided for checking whether there is <Provider> parent for <Consumer> child.

Generally, there is no difference if <Consumer> is inside or outside <Provider> with undefined value, it will be provided with undefined value in both cases.

It's possible to check current context value using internal _currentValue property, but this may result in false positives for undefined context value:

const ChildComponent = () => {
  if (NameConsumer._currentValue !== undefined) {
    // inside Provider
    return <NameConsumer>
      {context => <span>{context.name}</span>}
    </NameConsumer>
  } else {
    // no provider available, e.g. in a test file
    return <span>Test Text</span>
  }
}

Notice that this may not work as expected in asynchronous rendering, and relying on internals isn't recommended. A better way would be to check for test environment instead.

A more testable way is to use NameContext.Consumer consistently instead of NameConsumer, so Consumer property could be mocked in tests. Otherwise this may require to mock a module where NameConsumer is defined.

like image 98
Estus Flask Avatar answered Oct 06 '22 01:10

Estus Flask