Understanding the New Context API

Speaker

@emaSuriano

http://emanuelsuriano.design/

#100DaysOfCode

Gold Sponsor

What the f**k is Context? ๐Ÿค”

What is?

Context is another way of sharing information between parents and children (like props).

ย Using Props is an Explicit Communication.

While Context is an Implicit Communication.

// Via Props

<Parent>   props: {  value: 1 }  โ†“
  <Intermediate>   props: {  value: 1 }  โ†“
    <OtherIntermediate>    props: {  value: 1 }  โ†“
      <Child>    props: {  value: 1 }



// Via Context 

<Parent>   context: {  value: 1 }
  <Intermediate>
    <OtherIntermediate>
      <Child>    props: {  value: 1 }

Props

import React, { Component } from 'react';
import { number } from 'prop-types';

class Parent extends Component {
  render() {
    return <Child value={1}/>;
  }
}

class Child extends Component {
  static propTypes = {
    value: number
  };

  render() {
    const { value } = this.props;
    return (<p>
        The value from Context is: {value}
    </p>);
  }
}

Context

import React, { Component } from 'react';
import { number } from 'prop-types';

class Parent extends Component {
  static childContextTypes = {
    value: number
  };

  getChildContext() {
    return { value: 1 };
  }

  render() {
    return <Child />;
  }
}

class Child extends Component {
  static contextTypes = {
    value: number
  };

  render() {
    const { value } = this.context;
    return (<p>
        The value from Context is: {value}
    </p>);
  }
}

Why will you use it?

When an application starts to grow, is common to start seeing the Prop Drillingย problem.

This is having components passing down lots of props just to give access to component below of it ๐Ÿ‘Ž

Why did React rewrite Context?

The main flaw with context today is how it interacts with shouldComponentUpdate

๐Ÿ˜จ

What is going on?

shouldComponentUpdate returning false causes any Context update to be no longer propagated to Child Components

What does this new API offer?

Not Ready Yet โœ‹

Will come in React 16.3.0

List of Changes

  • Remove the need for using getChildContext to set values inside a context.
  • Remove contextType and childContextTypes static definition.
  • Add a new method React.createContext which create a new instance of a Context and return:
    • A Provider component allows you to define values inside the Context.
    • A Consumer component gives access to all the information inside the Context.

Old ๐Ÿ‘ด

import React, { Component } from 'react';
import { number } from 'prop-types';

class Parent extends Component {
  static childContextTypes = {
    value: string
  };

  getChildContext() {
    return { value: 1 };
  }

  render() {
    return <Child />;
  }
}

class Child extends Component {
  static contextTypes = {
    value: number
  };

  render() {
    const { value } = this.context;
    return (<p>
        The value from Context is: {value}
    </p>);
  }
}
import React, { createContext } from 'react';
import { number } from 'prop-types';

const { Provider, Consumer } = 
    createContext('contextExample')

const Parent = () => (
  <Provider value={ value: 1}>
    <Child />
  </Provider>
)

const Child = () => (
  <Consumer>
    ({value}) =>
      <p>The value from Context is: {value}</p>
  </Consumer>
)

Let's build something

๐Ÿ‘ท

โš ๏ธ Disclaimer โš ๏ธย 
No components with today context were wounded while refactoringย 

Task: Implement a RadioGroup

Responsibilities:

  • Render multiple radio buttons.
  • Radio buttons are assigned to the same group by a name property.
  • Only one radio button must be selected per group.

Implementing a RadioGroup

Vanilla React

Implementing a RadioGroup

With Context ๐Ÿ’ช

RadioGroupContext

This is the core communication of the library.

ย 

Create the context using the new API and return a Provider and Consumer.

//RadioGroupContext.js

import React from 'react';

const { Provider, Consumer } = 
    React.createContext('radioGroup');

export { Provider, Consumer };

RadioGroup

In charge of distributing the information to all the RadioButton:

  • Name of the group for the radio buttons,
  • The callback onChange.
  • The selected radio.
  • If the group is disabled
//RadioGroup.js
import React from 'react';
import { Provider } from './RadioGroupContext';

const RadioGroup =
({ selected, onChange, name, disabled, children }) => (
  <Provider
    value={{
      selected,
      onChange,
      name,
      disabledGroup: disabled,
    }}
  >
    {children}
  </Provider>
);


export default RadioGroup;

RadioButton

Read from the context defined by the RadioGroup and make some assumptions:

  • Selected === id, then checked = true
  • Disabled || disabledGroup, then disabled = true
  • !Value, then value = id
//RadioButton.js
import React from 'react';
import { Consumer } from './RadioGroupContext';

const RadioButton = ({ id, value, disabled, children }) => (
  <Consumer>
    {({ selected, onChange, disabledGroup, name }) => (
      <React.Fragment>
        <input
          type="radio"
          {...selected && { checked: selected === id }}
          disabled={disabled || disabledGroup}
          id={id}
          value={value || id}
          name={name}
          onChange={onChange}
        />
        <label htmlFor={id}>{children}</label>
      </React.Fragment>
    )}
  </Consumer>
);

export default RadioButton;

Great Examples using the New API

react-waterfall

import { initStore } from 'react-waterfall'

const store = {
  initialState: { count: 0 },
  actions: {
    increment: ({ count }) => ({ count: count + 1 }),
  },
}

const { Provider, connect } = initStore(store)

let Count = ({ state, actions }) => (
  <>
    {state.count}
    <button onClick={actions.increment}>+</button>
  </>
)

Count = connect(['count'])(Count)

const App = () => (
  <Provider>
    <Count />
  </Provider>
)

with-context

import { withContext } from "with-context";
import { styles } from "../consts";

export const ThemeContext = React.createContext("light");
export const withTheme = withContext(ThemeContext, "theme");

@withTheme
export default class StatefulComponent extends React.PureComponent {
  render() {
    const { theme } = this.props;
    return (
      <div style={styles[theme]}>StatefulComponent with theme: {theme}</div>
    );
  }
}

const StatelessFunctionalComponent = ({ theme }) => {
  return (
    <div style={styles[theme]}>
      StatelessFunctionalComponent with theme: {theme}
    </div>
  );
};

const StatelessWithTheme = withTheme(StatelessFunctionalComponent);

Last Words

" Think Context as a forbiddenย top-notch feature for building powerful components in React ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ

Links

Thanks for listening!

Happy code ๐Ÿ’ป

Understanding the new Context API

By Ema Suriano

Understanding the new Context API

Iโ€™m going to tell you my experience of rewriting a Component using this new Context API in React.

  • 1,296