Skip to content

Instantly share code, notes, and snippets.

@Paratron
Last active September 22, 2017 16:27
Show Gist options
  • Save Paratron/8b0a402b0954f286a410a65791a74fc7 to your computer and use it in GitHub Desktop.
Save Paratron/8b0a402b0954f286a410a65791a74fc7 to your computer and use it in GitHub Desktop.
React shared values component
/**
* Sometimes you need to create a component of which all instances should rely on the same data pool.
* Lets for example consider a country selector dropdown. No matter how much of them you use inside your
* application - the all should share the same list of countries. But passing that list down to each and
* every component instance via props is very tiresome and bloats your app.
*
* Behold: the shared value component pattern!
*/
import React from 'react';
import PropTypes from 'prop-types';
import Dropdown from 'myComponents/Dropdown';
// This country list will be used by ALL selectors in their render function.
let countryList = [];
// This is the list of update functions where each instance of the
// country list component will attach itself to.
const updaters = [];
const propTypes = {
/** The country value to be selected */
value: PropTypes.string,
/** An update function to pass a new country value to the application */
onChange: PropTypes.func,
};
const defaultProps = {
value: null,
onChange: null,
};
export default class CountrySelector extends React.Component{
constructor(props){
super(props);
// We are binding this, so it can be called from anywhere.
this.boundUpdate = this.forceUpdate.bind(this);
}
/**
* We put the bound update func to the instances array.
* We only do this after mounting to avoid errors.
*/
componentDidMount(){
updaters.push(this.boundUpdate);
}
/**
* If the component is detached from the DOM, we can also remove the
* update hook.
*/
componentWillUnmount(){
const index = updaters.indexOf(this.boundUpdate);
updaters.splice(index, 1);
}
render(){
const {
value,
onChange
} = this.props;
return (
<Dropdown
list={countryList}
value={value}
onChange={onChange}
/>
);
}
}
CountrySelector.propTypes = propTypes;
CountrySelector.defaultProps = defaultProps;
/**
* This will replace the countryList and will cause all instances of the
* country selector dropdown to re-render!
*/
CountrySelector.updateCountryList = (newCountryList) => {
countryList = newCountryList;
updaters.forEach(cb => cb());
};
// =======================================================================================================
/**
* So from anywhere in your application - for example in a REST call, you may now retrieve
* a new country list and propagate it to all instances of the component!
*/
fetch('myCountryList.json').then(CountrySelector.updateList);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment