Skip to content

Instantly share code, notes, and snippets.

@ryaninvents
Created June 21, 2019 20:44
Show Gist options
  • Save ryaninvents/28df179815da3773f1cb7876ce4f5a2a to your computer and use it in GitHub Desktop.
Save ryaninvents/28df179815da3773f1cb7876ce4f5a2a to your computer and use it in GitHub Desktop.
Hook-like state encapsulation in React class components
function shallowEquals(a, b) {
if (a.length !== b.length) return false;
return a.every((el, i) => el === b[i]);
}
const noop = () => {};
/**
*
* @param {Function} mount Utility function to run when inputs change.
* All arguments passed to `runEffect` are considered to be dependencies;
* everything else must be passed via closure.
*/
export default function createEffect(mount) {
let lastDeps = null;
let unmount = noop;
return function runEffect(...deps) {
if (lastDeps && shallowEquals(deps, lastDeps)) return;
// Something changed
unmount();
const mountResult = mount(...deps);
unmount = typeof mountResult === 'function' ? mountResult : noop;
lastDeps = deps;
};
}
import React from 'react';
import PropTypes from 'prop-types';
import createEffect from './createEffect';
const noop = () => {};
export default class EffectExample extends React.Component {
_setGreeting = (greeting) => this.setState({greeting});
_fetchGreeting = createEffect((name) => {
if (!name) return null;
let setGreeting = this._setGreeting;
fetch(`/api/greet?username=${name}`)
.then((response) => response.text())
.then((greeting) => setGreeting(greeting));
return () => {
// Low-effort way to prevent a race condition.
setGreeting = noop;
}
});
componentDidMount() {
const {name} = this.props;
this._fetchGreeting(name);
}
componentDidUpdate() {
const {name} = this.props;
this._fetchGreeting(name);
}
componentWillUnmount() {
this._fetchGreeting(null);
}
render() {
return (<div>Your customized greeting: {this.state.greeting}</div>);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment