Skip to content

Instantly share code, notes, and snippets.

@marcusgadbem
Created September 28, 2015 17:33
Show Gist options
  • Save marcusgadbem/6abf9d18ded3fcb3c2eb to your computer and use it in GitHub Desktop.
Save marcusgadbem/6abf9d18ded3fcb3c2eb to your computer and use it in GitHub Desktop.
React component pattern with a Store
export class APIRateLimitError extends Error {
constructor(err) {
super('API Rate limit.');
}
}
import { APIRateLimitError } from './errors.js';
var _query = {};
var _result = [];
var _changeListeners = [];
var _initCalled = false;
var SomeStore = module.exports = {
init: function (queryObject) {
if (_initCalled)
return;
_initCalled = true;
_query = queryObject;
},
fetchData: function() {
var self = this;
this.someAjaxFn()
.then((result) => {
// process result...
SomeStore.notifyChange();
})
/**
* Catch XHR errors
*/
.catch(APIRateLimitError, (err) => {
SomeStore.notifyChange();
});
},
someAjaxFn: function() {
return new BPromise((resolve, reject) => {
var endpoint = 'http://api.domain.com/endpoint'
$.ajax({
url: endpoint,
cache: true,
type: 'GET',
headers: { Accept: 'application/vnd.github.VERSION.raw' },
success: (result) => {
resolve(result);
},
error: (err) => {
this.checkResponseError(err.responseJSON, reject);
}
});
});
},
checkResponseError: function (err, reject) {
if (err && err.message && err.message.indexOf('API rate limit') >= 0) {
reject(new APIRateLimitError());
} else if (err && err.message == 'Not Found') {
reject(new AnotherError());
}
return new Error(err);
},
getData: function () {
return {
// return your data to component
}
},
/**
* Listeners/Notifiers
*/
notifyChange: function () {
_changeListeners.forEach(function (listener) {
listener();
});
},
addChangeListener: function (listener) {
_changeListeners.push(listener);
},
removeChangeListener: function (listener) {
_changeListeners = _changeListeners.filter(function (l) {
return listener !== l;
});
},
};
import React from 'react';
import SomeStore from './mystore-store.js';
module.exports = MyComponent = React.createClass({
/* Config (documentation) */
propTypes: {
arrayProp: React.PropTypes.array,
boolProp: React.PropTypes.bool,
funcProp: React.PropTypes.func,
numProp: React.PropTypes.number,
objProp: React.PropTypes.object,
stringProp: React.PropTypes.string.isRequired,
},
/* Init */
getInitialState: function () {
return {}
},
getDefaultProps: function () {
return {};
},
/* Mounting */
componentWillMount: function () {
SomeStore.init();
SomeStore.fetchData();
},
componentDidMount: function () {
SomeStore.addChangeListener(this._updateSomeState);
},
/* Updating */
componentWillReceiveProps: function(newProps={})
shouldComponentUpdate: function((newProps={}, newState={})
componentWillUpdate: function((newProps={}, newState={})
componentDidUpdate: function((prevProps={}, prevState={})
/* Unmounting */
componentWillUnmount: function () {
SomeStore.removeChangeListener(this.updateGithubState);
},
/* Helpers */
_updateSomeState: function () {
this.setState(SomeStore.getData());
},
_parseQuerySearch: function() { },
_resolveTemplate: function() { }
/* Render */
// Multi-line JSX
render: function () {
return (
<div>
{/* component markup */}
</div>
);
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment