iguazu falls with iguazu logo

We are excited to share Iguazu as an open-source project for simplifying data flows from many different sources (i.e., GraphQL, REST, RPC) in Redux applications. Redux provides predictable state transitions with the flux pattern; Iguazu is a pattern for populating that state with asynchronous data. Iguazu and the API adapters we are open-sourcing were created by our frameworks engineering team to address data-loading needs in our large React applications, and we anticipate it can help other teams as well.

Motivation

Larger applications typically need to consume many API types; for example, GraphQL and REST together. The separation of REST, GraphQL and other data into different stores imposed by other libraries that we studied would have added complexity that we didn’t think was required.

Iguazu allows us to have a single data store (Redux); enable controlled server-side rendering (SSR) depth; use data from various API types and styles; coordinate that data; and provide common information about the state of that data in a simple interface.

Data flows like a waterfall

If a React component relies on asynchronous data, it typically has to do four things:

  1. Define a load action responsible for fetching the asynchronous data.
  2. dispatch() the load action when the component mounts and when the component receives new props (these can change the data the component needs).
  3. Define a mapStateToProps function, and use selectors to retrieve the data from the Redux state.
  4. Determine whether the state is actually loaded based on the props the selectors return.

Iguazu seeks to simplify this flow into one step. Instead of using React Redux’s connect higher-order component (HOC) looking for a mapStateToProps function, Iguazu defines a connectAsync HOC that makes use of a loadDataAsProps function.

Note that as both connect and connectAsync are HOCs, using one does not preclude use of the other.

import React from 'react';
import { connectAsync } from 'iguazu';
import DataDisplay from './DataDisplay';

function MyContainer({ isLoading, loadedWithErrors, myData, myOtherData }) {
  if (isLoading()) {
    return <div>Loading</div>;
  }

  if (loadedWithErrors()) {
    return <div>Oh no! Something went wrong</div>;
  }

  return (
    <React.Fragment>
      <DataDisplay data={myData} />
      <DataDisplay data={myOtherData} />
    </React.Fragment>
  );
}

function queryMyData(param) {
  return (dispatch, getState) => {
    // there are API adapters later below that manage this boilerplate
    // this is a simplified example of what they're doing under the hood
    const { data, error } = getState().getIn(['path', 'to', 'myData', param]);
    const status = data || error ? 'complete' : 'loading';
    let promise;
    if (data) {
      promise = Promise.resolve(data);
    } else if (error) {
      promise = Promise.reject(error);
    } else {
      promise = dispatch(fetchMyData(param));
    }

    return { data, error, status, promise };
  };
}

function queryMyOtherData(param) { /* Essentially the same as queryMyData */ }

function loadDataAsProps({ store, ownProps }) {
  const { dispatch, getState } = store;
  return {
    myData: () => dispatch(queryMyData(ownProps.someParam)),
    myOtherData: () => dispatch(queryMyOtherData(getState().someOtherParam)),
  };
}

export default connectAsync({ loadDataAsProps })(MyContainer);

This pattern lends itself well as a common interface for multiple data sources, like REST, “REST,” REST-like, RPC, GraphQL and other APIs. This can be beneficial in larger applications that usually need multiple API types. We are also releasing the iguazu-rest and iguazu-graphql adapters as open source. An RPC adapter is coming soon.

Here is an example with iguazu-graphql.

import { queryGraphQLData } from 'iguazu-graphql';

function loadDataAsProps({ store: { dispatch }, ownProps }) {
  // schema endpoints are configured elsewhere, allowing decoupled reuse
  const endpointName = 'example-endpoint';
  const query = `
    query ($someParam: String) {
      path(someParam: $someParam) {
        to {
          data
        }
      }
    }
  `;
  const variables = { someParam: ownProps.someParam };
  return {
    myData: () => dispatch(queryGraphQLData({ endpointName, query, variables })),
  };
}

The definition of suspense is …

React’s new Suspense API is coming, and we think Iguazu is well-positioned for that shift. You might have noticed that the interface of the actions ({ status, promise, data, error }) is very similar to React’s example cache implementation. While Iguazu and simple-cache-provider were developed independently, they will be able to speak together very easily.

Community

We’ve benefitted from Iguazu, and we’re excited to see how Iguazu can help your applications too. There are many other features to Iguazu that we have found useful but haven’t discussed here. Check out the Iguazu repo for details!