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 }
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>);
}
}
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>);
}
}
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 👎
shouldComponentUpdate returning false causes any Context update to be no longer propagated to Child Components
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>
)
⚠️ Disclaimer ⚠️
No components with today context were wounded while refactoring
Responsibilities:
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 };
In charge of distributing the information to all the RadioButton:
//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;
Read from the context defined by the RadioGroup and make some assumptions:
//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;
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>
)
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);