(function() {
  var useState    = React.useState;
  var useEffect   = React.useEffect;
  var useCallback = React.useCallback;
  var useRef      = React.useRef;

  function useApi(fetchFn, deps) {
    var _s = useState({ data:null, loading:true, error:null });
    var state = _s[0], setState = _s[1];
    var mounted = useRef(true);

    useEffect(function() {
      mounted.current = true;
      return function() { mounted.current = false; };
    }, []);

    var execute = useCallback(function() {
      setState(function(s) { return Object.assign({}, s, { loading:true, error:null }); });
      fetchFn().then(function(data) {
        if (mounted.current) setState({ data:data, loading:false, error:null });
      }).catch(function(err) {
        if (mounted.current) setState(function(s) { return Object.assign({}, s, { loading:false, error:err.message }); });
      });
    }, deps || []);

    useEffect(function() { execute(); }, [execute]);

    return { data:state.data, loading:state.loading, error:state.error, refetch:execute };
  }

  window.useApi = useApi;
})();
