This package attempts to make it easier to work with Orbit.js in a React environment. In a nutshell it's a transform listener, updating a component props with records as they are changed. If you're familiar with redux in combination with react-redux, you already know how to use this package.
react-orbitjs requires React >= 16.8 and Orbit 0.15 or later.
yarn
yarn add developertown/react-orbitjs
Note: there is no published npm package at the moment, but part of C.I. is testing the latest build against projects that use this library.
See: "External partner tests" in travis.
import { useOrbit } from 'react-orbitjs';
export default function Example() {
  const { 
    dataStore, 
    subscriptions: { planets } 
  } = useOrbit({ planets: q => q.findRecords('planet') });
  
  return planets.map(planet => {
    const moons = dataStore.cache.query(q => q.findRelatedRecords(planet, 'moons');
    
    return (
      <Planet key={planet.id} planet={planet} moons={moons} />
    );
  });
}import { withOrbit } from 'react-orbitjs';
import { compose } from 'recompose';
import { withRouter } from 'react-router';
import Display from './display';
export default compose(
  withRouter,
  // NOTE: withOrbit is a cacheOnly querier
  withOrbit(({ project }) => ({
    // all of these will be passed as props to `Display` and will cause re-renders if any of 
    // the underlying data in the store for these records / queries changes
    project: (q) => q.findRecord(project),
    organization: (q) => q.findRelatedRecord(project, 'organization'),
    owner: (q) => q.findRelatedRecord(project, 'owner'),
  }))
)(Display);import { useQuery } from 'react-orbitjs';
export default function Example() {
  const { 
    isLoading, error, refetch, 
    result: { planets, stars} 
  } = useQuery({ planets: q => q.findRecords('planet') });
  if (isLoading) return <Loader />;
  if (error) return <Error error={error} />;
  return (
    <>
      {planets.map(planet => <Planet key={planet.id} planet={planet} />)}
    </>
  )
}import { query } from 'react-orbitjs';
import { compose } from 'recompose';
import Display from './display';
return compose(
  query(() => {
    return {
      users: (q) => q.findRecords(USER),
    };
  }),
)(Display);- 
Context / Data Store Access 
- 
Utilities 
- 
Errors 
- 
Utils 
The default ContextProvider that should be used in most applications. This will allow withOrbit and query to be used througout the application.
import * as React from 'react';
import { BrowserRouter } from 'react-router-dom';
import { APIProvider, strategies } from 'react-orbitjs';
// application imports
import { baseUrl } from '@data/store';
import { ReduxProvider } from '@store';
import { schema, keyMap } from '@data/schema';
import RootRoute from './routes/root';
export default class Application extends React.Component {
  render() {
    return (
      <APIProvider
        storeCreator={() =>
          strategies.pessimisticWithRemoteIds.createStore(baseUrl, schema, keyMap)
        }
      >
        <ReduxProvider>
          <BrowserRouter>
            <RootRoute />
          </BrowserRouter>
        </ReduxProvider>
      </APIProvider>
    );
  }
}Used for creating a Wrapper Context Provider to abstract away the creation of the orbit.js datastore.
Example from APIProvider
import * as React from 'react';
import { OrbitProvider } from 'react-orbitjs';
import Store from '@orbit/store';
import { Source } from '@orbit/data';
import { ICreateStoreResult } from 'react-orbitjs/strategies/pessimistic-with-remote-ids';
interface IProps {
  storeCreator: () => Promise<ICreateStoreResult>;
}
interface IState {
  store?: Store;
  sources?: { [sourceName: string]: Source };
}
export class APIProvider extends React.Component<IProps, IState> {
  state = { store: undefined, sources: undefined };
  constructor(props: any) {
    super(props);
    this.initDataStore.bind(this)();
  }
  async initDataStore() {
    const { store, sources } = await this.props.storeCreator();
    this.setState({ store, sources });
  }
  render() {
    const { store, sources } = this.state;
    if (!store || !sources) {
      return null;
    }
    return (
      <OrbitProvider dataStore={store} sources={sources}>
        {this.props.children}
      </OrbitProvider>
    );
  }
}withOrbit is a Higher-order Component that provides access to the store and data sources. It also allows you to subscribe to changes to the default store's cache.
import { withOrbit } from 'react-orbitjs';
import { compose } from 'recompose';
import { withRouter } from 'react-router';
import Display from './display';
export default compose(
  withRouter,
  withOrbit(({ project }) => ({
    // all of these will be passed as props to `Display` and will cause re-renders if any of 
    // the underlying data in the store for these records / queries changes
    project: (q) => q.findRecord(project),
    organization: (q) => q.findRelatedRecord(project, 'organization'),
    owner: (q) => q.findRelatedRecord(project, 'owner'),
    group: (q) => q.findRelatedRecord(project, 'group'),
    products: (q) => q.findRelatedRecords(project, 'products'),
  }))
)(Display);A hook for getting access to the orbit context within functional components.
import { useCache } from 'react-orbitjs';
export default function Example() {
  const { dataStore } = useCache();
  const planets = dataStore.cache.query(q => q.findRecords('planet'));
  return planets.map(planet => {
    return (
      <Planet key={planet.id} planet={planet} />
    );
  });
}A hook for querying a remote source for records
import { useQuery } from 'react-orbitjs';
export default function Example() {
  const { 
    isLoading, error, refetch, 
    result: { planets, stars} 
  } = useQuery({
    planets: q => q.findRecords('planet'),
    stars: q => q.findRecords('star')
  });
  if (isLoading) return <Loader />;
  if (error) return <Error error={error} />;
  return (
    <>
      {stars.map(star => <Star key={star.id} star={star} />)}
      {planets.map(planet => <Planet key={planet.id} planet={planet} />)}
    </>
  )
}query will make a network request directly using the remote data source.
import { query } from 'react-orbitjs';
import { compose } from 'recompose';
import Display from './display';
return compose(
  query(() => {
    return {
      users: [
        (q) => q.findRecords(USER),
        {
          label: 'Get Users for User Input Select',
          sources: {
            remote: {
              settings: { ...defaultSourceOptions() },
              include: ['group-memberships.group', 'organization-memberships.organization'],
            },
          },
        },
      ],
    };
  }),
)(Display);import { strategies, APIProvider } from 'react-orbitjs';
import { strategies } from 'react-orbitjs';
const strategy = strategies.pessimisticWithRemoteIds;
import { ErrorMessage } from 'react-orbitjs';
import { parseError } from 'react-orbitjs';
import { pushPayload } from 'react-orbitjs';
import { recordIdentityFrom } from 'react-orbitjs';
import { localIdFromRecordIdentity } from 'react-orbitjs';
import { remoteIdentityFrom } from 'react-orbitjs';
import { attributesFor } from 'react-orbitjs';
MIT