How does React Context work by using a function inside of a component

Viewed 850

How does this code work ? How can a function be called inside a component?

import React from 'react'

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

const App = () =>
    <ThemeContext.Provider value={'green'}>
        <ThemeContext.Consumer>
            {(value) => <button style={{ background: value }}>Hello Context!</button>}
        </ThemeContext.Consumer>
    </ThemeContext.Provider>

export default App

I am trying to understand React Context internals , While it is clear how Context/Provider/Consumer can be used I just don't seem to understand how this line actually works calling a function inside of a component

<ThemeContext.Consumer>
    {(value) => <button style={{ background: value }}>Hello Context!</button>}
</ThemeContext.Consumer>

Is it possible have the same pattern work inside of a custom component? This throws a warning 'Functions are not valid as a React child.

<div>
{(value)=><span>{value}</span>}
</div>
4 Answers

React Functions as Child Components

So if I'm getting this right, you are basically asking how you could get a component which is in the following format:

<MyComponent>
  {(name) => (
    <div>{name}</div>
  )}
</MyComponent>

These are called functions as children. You do it by managing the state or a variable in a component locally and you pass that state or variable to any other component in the app by implementing the children as a function in MyComponent.

So your MyComponent component will look something as follows:

class MyComponent extends React.Component { 
  render() {
    return (
      <div>
        {this.props.children('Scuba Steve')}
      </div>
    );
  }
}
MyComponent.propTypes = {
  children: React.PropTypes.func.isRequired,
};

This allows you to reuse MyComponent anywhere with the exact same state or variables but you could render it differently.

You would find this pattern quite a lot in libraries like react-final-form for example, where the library maintains a state and the users can "consume" that state and render it in anyway they want.

You can read more about it at this link and at this link as well.

Understand React Context internals

The React Context Consumer children is a function instead of typical string or React Element

<ThemeContext.Consumer>
  {(value) => <button style={{ background: value }}>Hello Context!</button>}
</ThemeContext.Consumer>

<div>
  Hey, I'm normal JSX
</div>

The above code will be transpiled to


React.createElement(ThemeContext.Consumer, null, function (value) {
    return React.createElement("button", {
      style: {
        background: value
      }
    }, "Hello Context!");
  })

React.createElement("div", null, "Hey, I'm normal JSX"))

You can see that the children (props.children) is a function.

<div>
   {(value)=><span>{value}</span>}
</div>

This code is mean that you declared a function inside <div>. (Not calling that function any more)

<ThemeContext.Consumer>
    {(value) => <button style={{ background: value }}>Hello Context!</button>}
</ThemeContext.Consumer>

This function will be called inside ThemeContext.Consumer then your element will render

I see that it as more of a javascript question than a react specific; react components at the end the day will become a function; javascript support function as first-class, so a function can be passed to other function as arguments ( or returned as value ) hence the higher the components and context API. So your question can be roughly translated to this code snippet:

function Theme (color) {
   /* some code maybe */
   return function Nav (TotalItems){
         return `I'll render a ${color} with ${TotalItems} TotalItems`;
   }
}

let redThemed = Theme( "dark red");
let navComp = redThemed(17);
console.log( navComp );
console.log( redThemed(12) );

let blueThemed = Theme( "light blue");
console.log( blueThemed(4) );

Related