Gustavo Mendonça
Gustavo Mendonça

Reputation: 2091

How to get the data from React Context Consumer outside the render

I am using the new React Context API and I need to get the Consumer data from the Context.Consumer variable and not using it inside the render method. Is there anyway that I can achieve this?

For examplify what I want:

console.log(Context.Consumer.value);

What I tested so far: the above example, tested Context.Consumer currentValue and other variables that Context Consumer has, tried to execute Context.Consumer() as a function and none worked.

Any ideas?

Upvotes: 33

Views: 54913

Answers (6)

Gary
Gary

Reputation: 2339

Here is a sample code from what I was trying for myself. Hope it helps.

import React from 'react';

const ThemeContext = React.createContext('light');

class ThemeContextComponent extends React.Component {
  static contextType = ThemeContext;
  render() {
    return <div>Testing the {this.context} </div>;
  }
}

function useTask(context) {
  return React.useContext(context);
}

function ThemeFunctionUseContextComponent(props) {
  return (
    <div>
      ThemeFunctionUseContextComponent: Testing the {useTask(ThemeContext)}{' '}
    </div>
  );
}

function ThemeFunctionContextComponent(props) {
  var contextType = ThemeContext;
  return (
    <div>
      ThemeFunctionContextComponent: Testing the context <br /> current Value: {contextType._currentValue}, <br />{' '}
      current value 2: {contextType._currentValue2}, <br /> default value:{' '}
      {contextType._defaultValue} <br /> Global Name: {contextType._globalName}{' '}
      <br /> ThreadCount: {contextType._threadCount}{' '}
    </div>
  );
}

function ThemeFunctionUseContextComponent(props) {
  var contextType = React.useContext(ThemeContext);
  return (
    <div>ThemeFunctionUseContextComponent: Testing the context {contextType} </div>
  );
}

function WithContext(Component) {
  return (props) => (
    <ThemeContext.Consumer>
      {(value) => <Component {...props} context={value} />}
    </ThemeContext.Consumer>
  )
}

function ThemeFunctionUseContextTwoComponent(props) {
  return <div>ThemeFunctionUseContextTwoComponent: Testing the context={props.context} </div>;
}

var ThemeFunctionUseContextThreeComponent = WithContext(
  ThemeFunctionUseContextTwoComponent
);

function ThemeComponent(props) {
  return <div>ThemeComponent: Testing the {props.theme} </div>;
}

class RectorComponent extends React.Component {
  render() {
    return <div>RectorComponent: Testing this {this.props.theme} </div>;
  }
}

export default function App() {
  return (
    <div>
      <h1>Hello Starter!</h1>

      <ThemeComponent theme="dark" />
      <br />
      <RectorComponent theme="dark" />
      <br />
      <ThemeContext.Provider value="dark">
        <ThemeContextComponent />
      </ThemeContext.Provider>
      <br />
      <ThemeContext.Provider value="dark">
        <ThemeFunctionContextComponent />
      </ThemeContext.Provider>
      <br />
      <ThemeContext.Provider value="dark">
        <ThemeFunctionUseContextThreeComponent />
      </ThemeContext.Provider>
      <br/>

      <ThemeContext.Provider value="dark">
        <ThemeFunctionUseContextComponent />
      </ThemeContext.Provider>
      <br />

    </div>
  );
}

I am not sure of side effects of following code usage:

function ElementWithContextFunctionPattern(Component) {
  return ((props) => (
    <ThemeContext.Consumer>
      {(context) => (
        <ThemeFunctionUseContextTwoComponent {...props} context={context} />
      )}
    </ThemeContext.Consumer>
  ))();
}

It can be used as :

export default function App() {
  return (
      <ThemeContext.Provider value="dark">
        <ElementWithContextFunctionPattern />
      </ThemeContext.Provider>
  )
}

Also have a look at this: Unable to run the function from the context

Upvotes: 0

Sebastien Horin
Sebastien Horin

Reputation: 11067

For the @wertzguy solution to work, you need to be sure that your store is defined like this:

// store.js
import React from 'react';

let user = {};
const UserContext = React.createContext({
  user,
  setUser: () => null
});

export { UserContext };

Then you can do

import { UserContext } from 'store';

console.log(UserContext._currentValue.user);

Upvotes: 2

Ankur Kedia
Ankur Kedia

Reputation: 3853

You can achieve this in functional components by with useContext Hook.

You just need to import the Context from the file you initialised it in. In this case, DBContext.

 const contextValue = useContext(DBContext);

Upvotes: 11

qwertzguy
qwertzguy

Reputation: 17687

You can via an unsupported getter:

YourContext._currentValue

Note that it only works during render, not in an async function or other lifecycle events.

Upvotes: 2

TN Yadav
TN Yadav

Reputation: 99

This is how it can be achieved.

 class BasElement extends React.Component {
  componentDidMount() {
    console.log(this.props.context);
  }

  render() {
    return null;
  }
}

const Element = () => (
  <Context.Consumer>
    {context =>
      <BaseMapElement context={context} />
    }
  </Context.Consumer>
)

Upvotes: 1

Shubham Khatri
Shubham Khatri

Reputation: 281626

Update

As of React v16.6.0, you can use the context API like:

class App extends React.Component {
    componentDidMount() {
       console.log(this.context);
    }
    render() {
       // render part here
       // use context with this.context
    }
}
App.contextType = CustomContext

However, the component can only access a single context. In order to use multiple context values, use the render prop pattern. More about Class.contextType.

If you are using the experimental public class fields syntax, you can use a static class field to initialize your contextType:

class MyClass extends React.Component {
  static contextType = MyContext;
  render() {
    let value = this.context;
    /* render something based on the value */
  }
}

Render Prop Pattern

When what I understand from the question, to use context inside your component but outside of the render, create a HOC to wrap the component:

const WithContext = (Component) => {
  return (props) => (
      <CustomContext.Consumer>
           {value =>  <Component {...props} value={value} />}
      </CustomContext.Consumer>
  )
}

and then use it:

class App extends React.Component {
    componentDidMount() {
       console.log(this.props.value);
    }
    render() {
       // render part here
    }
}
export default WithContext(App);

Upvotes: 33

Related Questions