Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In React component lifecycle methods, `this.context` is an empty Object

Tags:

reactjs

Why is this.context an empty object, in this React component lifecycle methods?

The context has the correct value in the Consumer for that context. Only the this.context API is failing.

const LoremContext = React.createContext({
    lorem: "ipsum",
})


class MenuItem extends React.Component {

    componentDidMount() {
        console.log(
            "In MenuItem.componentDidMount, this.context is:",
            this.context)
    }

    render() {
        console.log(
            "In MenuItem.render, this.context is:",
            this.context)
        return ( <LoremContext.Consumer>{
            (lorem) => {
                console.log("In LoremContext.Consumer, lorem is:", lorem)
                return (
                    <li>
                        { `Eat ${this.props.dish} at ${lorem}` }
                    </li>
                )
            }
        }</LoremContext.Consumer> )
    }
}

MenuItem.contextType = LoremContext

class Menu extends React.Component {
    render() {
        …
    }
}

class Application extends React.Component {
    render() {
        return (
            <LoremContext.Provider value={ this.props.world.lorem }>
                <section className="app">
                    <Menu menuItems={ [ … ] } />
                <p>Fusce varius id arcu egestas sodales</p>
            </section>
        </LoremContext.Provider>
    )
}

ReactDOM.render(
    <Application world={ { lorem: "consecteur" } } />,
    document.getElementById('app-container'),
)

This is using React 16.4, so it makes use of the documented context API (introduced in React 16.3).

According to that documented API, the above code should get access to the context (defined in the return value from React.createContext) in two ways:

  • The LoremContext.Consumer component receives the context value passed by the LoremContext.Provider.

    The consumer then provides that context value as an argument to the function within that component. In this case, lorem is the argument that receives the context value.

  • The this.context property receives (because of the declared MenuItem.contextType class property) the context value, inside the “lifecycle methods”.

Only one of those is working for me.

  • The LoremContext.Consumer API is getting and passing the context value correctly. The console.log output is:
  In LoremContext.Consumer, lorem is: consecteur
  • The this.context is not getting the correct value, instead it gets an empty Object. The console.log output is:
  In MenuItem.render, context is: Object {  }
  In MenuItem.componentDidMount, context is: Object {  }

So the consumer is receiving the correct value, but this.context is not. Why the difference? How can I get the correct value received at this.context?

like image 955
bignose Avatar asked Oct 24 '18 11:10

bignose


People also ask

What are the lifecycle methods of React components?

Lifecycle of Components Each component in React has a lifecycle which you can monitor and manipulate during its three main phases. The three phases are: Mounting, Updating, and Unmounting.

What is this context in React?

What is React context? React context allows us to pass down and use (consume) data in whatever component we need in our React app without using props. In other words, React context allows us to share data (state) across our components more easily.

Is componentDidUpdate called after componentDidMount?

The componentDidUpdate()is called after componentDidMount() and can be useful to perform some action when the state of the component changes. Parameters: Following are the parameter used in this function: prevProps: Previous props passed to the component. prevState: Previous state of the component.

How many times is componentDidMount called in a component's lifecycle?

2. How many times componentDidMount is called? React components call componentDidMount only once by default. You can run the component multiple times if you delete the component or change the props or state.


3 Answers

this.context was introduced in React 16.6 that you see can see here

Before this version, on 16.4, that you are using, accessing context inside React Lifecycles can be achieved:

class Button extends React.Component {
  componentDidMount() {
    // ThemeContext value is this.props.theme
  }

  componentDidUpdate(prevProps, prevState) {
    // Previous ThemeContext value is prevProps.theme
    // New ThemeContext value is this.props.theme
  }

  render() {
    const {theme, children} = this.props;
    return (
      <button className={theme || 'light'}>
        {children}
      </button>
    );
  }
}

export default props => (
  <ThemeContext.Consumer>
    {theme => <Button {...props} theme={theme} />}
  </ThemeContext.Consumer>
);

See docs for more information

like image 85
Agney Avatar answered Sep 28 '22 08:09

Agney


Try creating the context in a separate file and then importing it. That worked for me. When createContext was called in the same file where the <MyContext.Provider> tag was used, the consumers only saw an empty object. When I moved createContext to a separate file, the consumers saw the expected values. This applies to both methods of consuming - <MyContext.Consumer> and MyClass.contextType/this.context.

I'm afraid I can't explain why this works, but I found the solution in this thread.

like image 29
James Beninger Avatar answered Sep 28 '22 06:09

James Beninger


Unfortunatelly without this part in the target component it is empty.

static contextType = ThemeContext; // assign the correct context 

before created like

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

https://reactjs.org/docs/context.html

like image 31
luky Avatar answered Sep 28 '22 06:09

luky