{"id":268113,"date":"2018-03-21T09:25:56","date_gmt":"2018-03-21T16:25:56","guid":{"rendered":"http:\/\/css-tricks.com\/?p=268113"},"modified":"2018-03-27T11:05:22","modified_gmt":"2018-03-27T18:05:22","slug":"putting-things-in-context-with-react","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/putting-things-in-context-with-react\/","title":{"rendered":"Putting Things in Context With React"},"content":{"rendered":"

Context<\/a> is currently an experimental API for React – but soon to be a first class citizen<\/a>! There are a lot of reasons it is interesting but perhaps the most is that it allows for parent components to pass data implicitly to their children, no matter how deep the component tree is. In other words, data can be added to a parent component and then any child can tap into it.<\/p>\n

<\/p>\n

See the Pen React Context Lights<\/a> by Neal Fennimore (@nealfennimore<\/a>) on CodePen<\/a>.<\/p>\n

While this is often the use case for using something like Redux<\/a>, it\u2019s nice to use if you do not need complex data management. Think about that! We create a custom downstream of data, deciding which props are passed and at which levels. Pretty cool.<\/p>\n

Context is great in areas of where you have a lot of components that depend on a single piece of data, but are deep within the component tree. Explicitly passing each prop to each individual component can often be overwhelming and it is a lot easier just to use context here.<\/p>\n

For example, let\u2019s consider how we would normally pass props down the tree. In this case, we\u2019re passing the color red<\/code> using props on each component in order to move it on down the stream.<\/p>\n

class Parent extends React.Component {\r\n  render(){\r\n    return <Child color=\"red\" \/>;\r\n  }\r\n}\r\n\r\nclass Child extends React.Component {\r\n  render(){\r\n    return <GrandChild color={this.props.color} \/>\r\n  }\r\n}\r\n\r\nclass GrandChild extends React.Component {\r\n  render(){\r\n    return (\r\n      <div style={{color: this.props.color}}>\r\n        Yep, I'm the GrandChild\r\n      <\/div>\r\n    );\r\n  }\r\n}<\/code><\/pre>\n

What if we never wanted the Child<\/code> component to have the prop in the first place? Context saves us having to go through the Child<\/code> component with color and pass it directly from the Parent<\/code> to the GrandChild<\/code>:<\/p>\n

class Parent extends React.Component {\r\n  \/\/ Allow children to use context\r\n  getChildContext() {\r\n    return {\r\n      color: 'red'\r\n    };\r\n  }\r\n  \r\n  render(){\r\n    return <Child \/>;\r\n  }\r\n}\r\n\r\nParent.childContextTypes = {\r\n  color: PropTypes.string\r\n};\r\n\r\nclass Child extends React.Component {\r\n  render() {\r\n    \/\/ Props is removed and context flows through to GrandChild\r\n    return <GrandChild \/>\r\n  }\r\n}\r\n\r\nclass GrandChild extends React.Component {\r\n  render() {\r\n    return (\r\n      <div style={{color: this.context.color}}>\r\n        Yep, I'm still the GrandChild\r\n      <\/div>\r\n    );\r\n  }\r\n}\r\n\r\n\/\/ Expose color to the GrandChild\r\nGrandChild.contextTypes = {\r\n  color: PropTypes.string\r\n};<\/code><\/pre>\n

While slightly more verbose, the upside is exposing the color<\/code> anywhere down in the component tree. Well, sometimes\u2026<\/p>\n

There\u2019s Some Gotchas<\/h3>\n

You can\u2019t always have your cake and eat it too, and context in it\u2019s current form is no exception. There are a few underlying issues that you\u2019ll more than likely come into contact with, if you end up using context for all but the simplest cases.<\/p>\n

Context is great for being used on an initial render. Updating context on the fly? Not so much. A common issue with context is that context changes are not<\/strong> always reflected in a component.<\/p>\n

Let\u2019s dissect these gotchas in more detail.<\/p>\n

Gotcha 1: Using Pure Components<\/h4>\n

Context is hard when using PureComponent<\/code><\/a>, since by default it does not perform any shallow diffing with context. Shallow diffing<\/a> with PureComponent<\/code> is testing for whether the values of the object are strictly equal. If they’re not, then (and only then) will the component update. But since context is not checked, well… nothing happens.<\/p>\n

See the Pen React Context Lights with PureComponents<\/a> by Neal Fennimore (@nealfennimore<\/a>) on CodePen<\/a>.<\/p>\n

Gotcha 2: Should Component Update? Maybe.<\/h4>\n

Context also does not update if a component\u2019s shouldComponentUpdate<\/code> returns false<\/code>. If you have a custom shouldComponentUpdate<\/code> method, then you\u2019ll also need to take context into consideration. To enable updates with context, we could update each individual component with a custom shouldComponentUpdate<\/code> that looks something like this.<\/p>\n

import shallowEqual from 'fbjs\/lib\/shallowEqual';\r\n\r\nclass ComponentThatNeedsColorContext extends React.PureComponent {\r\n  \/\/ nextContext will show color as soon as we apply ComponentThatNeedsColorContext.contextTypes\r\n  \/\/ NOTE: Doing the below will show a console error come react v16.1.1\r\n  shouldComponentUpdate(nextProps, nextState, nextContext){\r\n    return !shallowEqual(this.props, nextProps) || !shallowEqual(this.state, nextState) || !shallowEqual(this.context, nextContext);\r\n  }\r\n}\r\n\r\nComponentThatNeedsColorContext.contextTypes = {\r\n  color: PropTypes.string\r\n};<\/code><\/pre>\n

However, this does not solve the issue of an intermediary PureComponent<\/code> between the parent and the child blocking context updates. This means that every PureComponent<\/code> between the parent and child would need to have contextTypes<\/code> defined on it, and they would also need to have an updated shouldComponentUpdate<\/code> method. And at this point, that’s a lot of work for very little gain.<\/p>\n

Better Approaches to the Gotchas<\/h3>\n

Fortunately, we have some ways to work around the gotchas.<\/p>\n

Approach 1: Use a Higher Order Component<\/h4>\n

A Higher Order Component<\/a> can read from context and pass the needed values on to the next component as a prop.<\/p>\n

import React from 'react';\r\n\r\nconst withColor = (WrappedComponent) => {\r\n    class ColorHOC extends React.Component {\r\n        render() {\r\n            const { color } = this.context;        \r\n            return <WrappedComponent style={{color: color}} {...this.props} \/>\r\n        }\r\n    }\r\n         \r\n    ColorHOC.contextTypes = {\r\n        color: React.PropTypes.string  \r\n    };\r\n\r\n    return ColorHOC;\r\n};\r\n\r\n\r\nexport const Button = (props)=> <button {...props}>Button<\/button>\r\n\r\n\/\/ ColoredButton will render with whatever color is currently in context with a style prop\r\nexport const ColoredButton = withColor( Button );<\/code><\/pre>\n

See the Pen React Context Lights with HOC<\/a> by Neal Fennimore (@nealfennimore<\/a>) on CodePen<\/a>.<\/p>\n

Approach 2: Use Render Props<\/h4>\n

Render Props<\/a> allow us to use props to share code between two components. <\/p>\n

class App extends React.Component {\r\n    getChildContext() {\r\n        return {\r\n            color: 'red'\r\n        }\r\n    }\r\n\r\n    render() {\r\n        return <Button \/>\r\n    }\r\n}\r\n\r\nApp.childContextTypes = {\r\n    color: React.PropTypes.string\r\n}\r\n\r\n\/\/ Hook 'Color' into 'App' context\r\nclass Color extends React.Component {\r\n    render() {\r\n        return this.props.render(this.context.color);\r\n    }\r\n}\r\n\r\nColor.contextTypes = {\r\n    color: React.PropTypes.string\r\n}\r\n\r\nclass Button extends React.Component {\r\n    render() {\r\n        return (\r\n            <button type=\"button\">\r\n                {\/* Return colored text within Button *\/}\r\n                <Color render={ color => (\r\n                    <Text color={color} text=\"Button Text\" \/>\r\n                ) } \/>\r\n            <\/button>\r\n        )\r\n    }\r\n}\r\n\r\nclass Text extends React.Component {\r\n    render(){\r\n        return (\r\n            <span style={{color: this.props.color}}>\r\n                {this.props.text}\r\n            <\/span>\r\n        )\r\n    }\r\n}\r\n\r\nText.propTypes = {\r\n    text: React.PropTypes.string,\r\n    color: React.PropTypes.string,\r\n}<\/code><\/pre>\n

Approach 3: Dependency Injection<\/h4>\n

A third way we can work around these gotchas is to use Dependency Injection<\/a> to limit the context API and allow components to subscribe as needed.<\/p>\n

The New Context<\/h3>\n

The new way of using context, which is currently slated for the next minor release of React (16.3)<\/a>, has the benefits of being more readable and easier to write without the \u201cgotchas\u201d from previous versions. We now have a new method called createContext<\/code>, which defines a new context and returns both a Provider<\/code> and Consumer<\/code>. <\/p>\n

The Provider<\/code> establishes a context that all sub-components can hook into. It\u2019s hooked in via Consumer<\/code> which uses a render prop. The first argument of that render prop function, is the value<\/code> which we have given to the Provider<\/code>. By updating the value within the Provider<\/code>, all consumers will update to reflect the new value.<\/p>\n

As a side benefit with using the new context, we no longer have to use childContextTypes<\/code>, getChildContext<\/code>, and contextTypes<\/code>.<\/p>\n

const ColorContext = React.createContext('color');\r\nclass ColorProvider extends React.Component {\r\n    render(){\r\n        return (\r\n            <ColorContext.Provider value={'red'}>\r\n                { this.props.children }\r\n            <\/ColorContext.Provider>\r\n        )\r\n    }\r\n}\r\n\r\nclass Parent extends React.Component {  \r\n    render(){\r\n        \/\/ Wrap 'Child' with our color provider\r\n        return (\r\n            <ColorProvider>\r\n                <Child \/>\r\n            <\/ColorProvider>\r\n        );\r\n    }\r\n}\r\n\r\nclass Child extends React.Component {\r\n    render(){\r\n        return <GrandChild \/>\r\n    }\r\n}\r\n\r\nclass GrandChild extends React.Component {\r\n    render(){\r\n        \/\/ Consume our context and pass the color into the style attribute\r\n        return (\r\n            <ColorContext.Consumer>\r\n                {\/* 'color' is the value from our Provider *\/}\r\n                {\r\n                    color => (\r\n                        <div style={{color: color}}>\r\n                            Yep, I'm still the GrandChild\r\n                        <\/div>\r\n                    )\r\n                }\r\n            <\/ColorContext.Consumer>\r\n        );\r\n    }\r\n}<\/code><\/pre>\n

Separate Contexts<\/h3>\n

Since we have more granular control in how we expose context and to what components are allowed to use it, we can individually wrap components with different contexts, even if they live within the same component. We can see this in the next example, whereby using the LightProvider<\/code> twice, we can give two components a separate context.<\/p>\n

See the Pen React Context Lights with new Context<\/a> by Neal Fennimore (@nealfennimore<\/a>) on CodePen<\/a>.<\/p>\n

Conclusion<\/h3>\n

Context is a powerful API, but it’s also very easy to use incorrectly. There are also a few caveats to using it, and it can be very hard to figure out issues when components go awry. While Higher-Order Components and dependency injection offer alternatives for most cases, context can be used beneficially in isolated portions of your code base.<\/p>\n

With the next context though, we no longer have to worry about the gotchas we had with the previous version. It removes having to define contextTypes<\/code> on individual components and opens up the potential for defining new contexts in a reusable manner. <\/p>\n","protected":false},"excerpt":{"rendered":"

Context is currently an experimental API for React – but soon to be a first class citizen! There are a […]<\/p>\n","protected":false},"author":252032,"featured_media":268114,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_bbp_topic_count":0,"_bbp_reply_count":0,"_bbp_total_topic_count":0,"_bbp_total_reply_count":0,"_bbp_voice_count":0,"_bbp_anonymous_reply_count":0,"_bbp_topic_count_hidden":0,"_bbp_reply_count_hidden":0,"_bbp_forum_subforum_count":0,"inline_featured_image":false,"c2c_always_allow_admin_comments":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"_share_on_mastodon":"0","_share_on_mastodon_status":"%title% %permalink%"},"categories":[4],"tags":[557,562],"class_list":["post-268113","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-articles","tag-react","tag-react-props"],"acf":{"show_toc":"No"},"share_on_mastodon":{"url":"","error":""},"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/03\/react-congtext-lights.gif?fit=1200%2C600&ssl=1","jetpack-related-posts":[{"id":271882,"url":"https:\/\/css-tricks.com\/digging-into-react-context\/","url_meta":{"origin":268113,"position":0},"title":"Digging Into React Context","author":"Kingsley Silas","date":"June 11, 2018","format":false,"excerpt":"You may have wondered lately what all the buzz is about Context and what it might mean for you and your React sites. Before Context, when the management of state gets complicated beyond the functionality of setState, you likely had to make use of a third party library. Thanks to\u2026","rel":"","context":"In "Articles"","block_context":{"text":"Articles","link":"https:\/\/css-tricks.com\/category\/articles\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/05\/react-context.jpg?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/05\/react-context.jpg?fit=1200%2C600&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/05\/react-context.jpg?fit=1200%2C600&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/05\/react-context.jpg?fit=1200%2C600&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/05\/react-context.jpg?fit=1200%2C600&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":281073,"url":"https:\/\/css-tricks.com\/intro-to-react-hooks\/","url_meta":{"origin":268113,"position":1},"title":"Intro to React Hooks","author":"Kingsley Silas","date":"January 18, 2019","format":false,"excerpt":"Hooks make it possible to organize logic in components, making them tiny and reusable without writing a class. In a sense, they\u2019re React\u2019s way of leaning into functions because, before them, we\u2019d have to write them in a component and, while components have proven to be powerful and functional in\u2026","rel":"","context":"In "Articles"","block_context":{"text":"Articles","link":"https:\/\/css-tricks.com\/category\/articles\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2019\/01\/coat-rack-hooks.png?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2019\/01\/coat-rack-hooks.png?fit=1200%2C600&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2019\/01\/coat-rack-hooks.png?fit=1200%2C600&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2019\/01\/coat-rack-hooks.png?fit=1200%2C600&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2019\/01\/coat-rack-hooks.png?fit=1200%2C600&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":278638,"url":"https:\/\/css-tricks.com\/compound-components-in-react-using-the-context-api\/","url_meta":{"origin":268113,"position":2},"title":"Compound Components in React Using the Context API","author":"Kingsley Silas","date":"December 6, 2018","format":false,"excerpt":"Compound components in React allow you to create components with some form of connected state that\u2019s managed amongst themselves. A good example is the Form component in Semantic UI React. To see how we can implement compound components in a real-life React application, we\u2019ll build a compound (multi-part) form for\u2026","rel":"","context":"In "Articles"","block_context":{"text":"Articles","link":"https:\/\/css-tricks.com\/category\/articles\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/11\/compound-components-featured.png?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/11\/compound-components-featured.png?fit=1200%2C600&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/11\/compound-components-featured.png?fit=1200%2C600&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/11\/compound-components-featured.png?fit=1200%2C600&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/11\/compound-components-featured.png?fit=1200%2C600&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":280606,"url":"https:\/\/css-tricks.com\/using-react-portals-to-render-children-outside-the-dom-hierarchy\/","url_meta":{"origin":268113,"position":3},"title":"Using React Portals to Render Children Outside the DOM Hierarchy","author":"Kingsley Silas","date":"January 14, 2019","format":false,"excerpt":"Say we need to render a child element into a React application. Easy right? That child is mounted to the nearest DOM element and rendered inside of it as a result. render() { return ( \/\/ Child to render inside of the div ); } But! What if we want\u2026","rel":"","context":"In "Articles"","block_context":{"text":"Articles","link":"https:\/\/css-tricks.com\/category\/articles\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/12\/weird-swirl.png?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/12\/weird-swirl.png?fit=1200%2C600&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/12\/weird-swirl.png?fit=1200%2C600&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/12\/weird-swirl.png?fit=1200%2C600&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/12\/weird-swirl.png?fit=1200%2C600&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":239591,"url":"https:\/\/css-tricks.com\/learning-react-container-components\/","url_meta":{"origin":268113,"position":4},"title":"Leveling Up With React: Container Components","author":"Brad Westfall","date":"March 21, 2016","format":false,"excerpt":"This tutorial is the second of a three-part series on React by Brad Westfall. This series is all about going beyond basic React skills and building bigger things, like entire Single Page Applications (SPAs). This article picks up where the last article, on React Router, left off. Article Series: React\u2026","rel":"","context":"In "Articles"","block_context":{"text":"Articles","link":"https:\/\/css-tricks.com\/category\/articles\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":273438,"url":"https:\/\/css-tricks.com\/render-children-in-react-using-fragment-or-array-components\/","url_meta":{"origin":268113,"position":5},"title":"Render Children in React Using Fragment or Array Components","author":"Kingsley Silas","date":"July 17, 2018","format":false,"excerpt":"What comes to your mind when React 16 comes up? Context? Error Boundary? Those are on point. React 16 came with those goodies and much more, but In this post, we'll be looking at the rendering power it also introduced \u2014 namely, the ability to render children using Fragments and\u2026","rel":"","context":"In "Articles"","block_context":{"text":"Articles","link":"https:\/\/css-tricks.com\/category\/articles\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/04\/react.jpg?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/04\/react.jpg?fit=1200%2C600&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/04\/react.jpg?fit=1200%2C600&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/04\/react.jpg?fit=1200%2C600&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/04\/react.jpg?fit=1200%2C600&ssl=1&resize=1050%2C600 3x"},"classes":[]}],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/268113","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/users\/252032"}],"replies":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/comments?post=268113"}],"version-history":[{"count":12,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/268113\/revisions"}],"predecessor-version":[{"id":268983,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/268113\/revisions\/268983"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/media\/268114"}],"wp:attachment":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/media?parent=268113"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/categories?post=268113"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/tags?post=268113"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}