Created
February 4, 2016 13:30
-
-
Save Robert-W/7a1cde76e1d9edde1b93 to your computer and use it in GitHub Desktop.
Example of Using context in React with ES6 Classes to pass a reference to a map object around
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import appActions from 'actions/AppActions'; | |
import React, {Component, PropTypes} from 'react'; | |
import {mapConfig} from 'js/config'; | |
import EsriMap from 'esri/map'; | |
class Map extends Component { | |
//- Define your context types here as static property | |
static childContextTypes = { | |
map: PropTypes.object | |
}; | |
//- Define a method to get the context | |
getChildContext = () => { | |
return { map: this.map }; | |
}; | |
constructor (props) { | |
super(props); | |
//- IMPORTANT: Set map to an empty object so children can check if map.loaded has changed | |
this.map = {}; | |
} | |
componentDidMount () { | |
this.map = new EsriMap(this.refs.map, mapConfig.options); | |
//- At this point, any children will have an empty map object, to make sure they receive it once it is created | |
//- fire off an action to trigger a change event, this will rerender and then this.context.map will be Esri's Map Object | |
this.map.on('load', appActions.mapUpdated); | |
} | |
render () { | |
return ( | |
<div ref='map' className='map'> | |
<MapControls /> | |
</div> | |
); | |
} | |
} | |
class MapControls extends Component { | |
//- Define the context that I will need | |
static contextTypes = { | |
map: PropTypes.object.isRequired | |
}; | |
componentDidUpdate (prevProps, prevState, prevContext) { | |
//- I am logging this here to demonstrate that after appActions.mapUpdated fires this.context.map will contain Esri's Map Object | |
console.log(this.context.map); | |
//- Check if the map exists so you can create an esri component with it, here im looking for a change in the loaded property | |
let {map} = this.context; | |
let {prevMap} = prevContext; | |
if (prevMap.loaded !== map.loaded) { | |
// We are Ready | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Putting this up as an example. Context is a changing API as React's core team still seems to be evolving it until they can determine a Public API that works with everything.
One Catch
Right now componentShouldUpdate is a good way of manually pruning the tree recalculation, but this can cause issues. If your component declares context, it will receive prevContext as a third parameter and can check it, if not, then it wont. So things similar to pureRenderMixin won't work. Consider this:
If parent declares context, but middle does not, and child depends on context, this can be difficult if context changes. If Middle uses shouldComponentUpdate and returns true, the child wont receive the updated context. We also don't want Middle to be aware of it's children as that would complicate things. So you should be careful using context for something like a Map because if the map changes, and a middle component implements shouldComponentUpdate, it may prevent a child from getting the updated context.
See here for more: facebook/react#2517
An alternate solution
Create the map the same way and pass it as props, this is also a little painful as all middle components must explicitly pass props down and the map is mutable so detecting changes on it in shouldComponentUpdate will be difficult anyway