3

I am trying to understand the React context API and was going through the official docs. I will appreciate if someone can throw some more light on the following points as the official doc does not address it clearly.

  1. What is the difference in contextType and Consumer methods to consume the values provided by Provider? In what situation we should use which method?
  2. Can the value exposed by Provider in a class based component, be used by a react hook component using useContext? I had the same setup and i ended up converting the useContext to Context.Consumer.
  3. I have a very straightforward setup in which i have a Provider Class based component which is exposing some state values. The Provider has only one children component which is also a consumer. When i use Context.Consumer in the children to fetch the values, everything works as expected. But when i use contextType in the children component, i see an empty object.

ContextProvider.js

import React from "react";
import {ContextConsumer} from "./ContextConsumer";
export const TestContext = React.createContext({
    count: 1,
    incrCount: (count)=>{
     console.log(`count value :- ${count}`)
     }
});

export class ContextProvider extends React.Component {
  incrCount = () => {
    this.setState({
      count: this.state.count + 1,
    });
  };

  state = {
    count: 5,
    incrCount: this.incrCount,
  };

  render() {
    return (
      <TestContext.Provider value={this.state}>
        <ContextConsumer />
      </TestContext.Provider>
    );
  }
}

ContextConsumer.js

import React from "react";
import { TestContext } from "./ContextProvider";

export class ContextConsumer extends React.Component {
    static contextType=TestContext

  componentDidMount() {
        const {count,incrCount}= this.context;
        console.log(`count:- ${(count)}`)
        console.log(`incrCount:- ${incrCount}`)
    }
  render() {


    return (
      <div>


        **// BELOW CODE IS WORKING AS EXPECTED**
        <TestContext.Consumer>
          {({ count, incrCount }) => (
            <button onClick={incrCount}>Count is {count}</button>
          )}
        </TestContext.Consumer>
      </div>
    );
  }
}

App.js

import {ContextProvider}  from "../../playground/ContextProvider";

const output = (
  <Provider store={reduxStore}>
    <ContextProvider />
  </Provider>
);

ReactDOM.render(output, document.getElementById("root"));
ryan
  • 416
  • 3
  • 15
  • 1
    I think you are on a version of react between v16.3.0 - v16.6.0. The contextType support was introduced in 16.6.0. Please check this post https://stackoverflow.com/questions/49870098/how-to-get-the-data-from-react-context-consumer-outside-the-render/49870973#49870973 – Shubham Khatri Jun 19 '20 at 06:40
  • Yeah i am on 16.13.1 currently. But the information related to version support is not there on the context page https://reactjs.org/docs/context.html – ryan Jun 19 '20 at 06:43
  • 1
    @ryna, the docs show the APIs for latest version, you need to check the release notes for specific API introduction:: https://reactjs.org/blog/2018/10/23/react-v-16-6.html – Shubham Khatri Jun 19 '20 at 06:49

2 Answers2

5

What is the difference in contextType and Consumer methods to consume the values provided by Provider? In what situation we should use which method?

The static contextType assignment was introduced in v16.6.0 as a way to use context outside of render method. The only difference between Consumer and static context is the fact that using contextType allows you use context outside of render method too

Can the value exposed by Provider in a class based component, be used by a react hook component using useContext?

Yes the context value from Provider can be used by useContext too. However you can only make use of useContext inside a functional component and not a class component and also after v16.8.0 or react which supports hooks

P.S. You must ensure one thing that you are not causing a circular dependency by importing provider in consumer component and also the other way around

Edit FORM VALUES

Shubham Khatri
  • 211,155
  • 45
  • 305
  • 318
  • I was also referring one article online which says that Using Consumer is a traditional and legacy way of consuming the provider values. Is that true? If that is the case, are we only use contextType but based on your reply, i would think otherwise. https://www.taniarascia.com/using-context-api-in-react/. "The traditional way to retrieve Context values was by wrapping the child component in the Consumer. From there, you would be able to access the value prop as props. You may still see this, but it's more of a legacy way of accessing Context." – ryan Jun 19 '20 at 06:57
  • 2
    @ryan The context api has changed many times. Initially we needed to defined contextType but also for the provider we would use childContextTypes. Then in v16.3 react introduced the provider consumer apis which became popular and easy but had a drawback of using customization to use context outside of render function, so in v16.6.0 they improved on it and added the static contextType support so that we can use contextType in other lifecycles too. Then with the advent of hooks they introduced useContext to consume context in functional components. – Shubham Khatri Jun 19 '20 at 07:01
  • 1
    So while contextType is legacy way, its also the latest way of using context. – Shubham Khatri Jun 19 '20 at 07:01
  • I made the changes and have moved the "console.log(this.context)" inside componentDidMount from render, still i see the values as undefined. What am i missing here? – ryan Jun 19 '20 at 07:22
  • 1
    Probably a circular dependency. create the context in a separate file instead of in provider – Shubham Khatri Jun 19 '20 at 07:26
0
  1. Static contextType and class.contextType
  2. useContext
  3. context.Consumer

are almost same the difference between them is that (1) is used in class component and useContext is a hook and the best thing is we can use this hook multiple times in one functional component.(3) can only be used in jsx or in render(return).(1)and(2) can be used outside return.

Bilal Yaqoob
  • 27
  • 1
  • 10