useResource

useResource is the primary way to fetch data with Atomic React. It returns a Resource object, that is still loading when initially returned. When the data is loaded, the component will re-render with the new data allowing you to show some UI before the content is available, resulting in a more responsive user experience.

The hook also subscribes to changes meaning that the component will update whenever the data changes clientside and even serverside. You essentially get real-time features for free!

import { useResource } from '@tomic/react';

export const Component = () => {
  const resource = useResource('https://my-atomic-server/my-resource');

  // Optionally show a loading state
  if (resource.loading) {
    return <Loader />
  }

  return (
    <p>{resource.title}</p>
  )
}

Typescript

Just like the store.getResource method, useResource can be annotated with a subject of a certain class.

import { useResource } from '@tomic/react';
import type { Author } from './ontologies/blogsite' // <-- Generated with @tomic/cli

// ...
const resource = useResource<Author>('https://my-atomic-server/moderndayshakespear69')
const age = Date.now() - resource.props.yearOfBirth

Reference

Parameters

  • subject: string - The subject of the resource you want to fetch.
  • options: FetchOpts - (Optional) Options for how the store should fetch the resource.

FetchOpts:

NameTypeDescription
allowIncompleteboolean?
noWebSocketboolean(Optional) If true, uses HTTP to fetch resources instead of websockets
newResourceResource(Optional) If true, will not send a request to a server, it will simply create a new local resource.

Returns

Resource - The fetched resource (might still be in a loading state).

Views

A common way to build interfaces with Atomic React is to make a view component. Views are a concept where the component is responsible for rendering a resource in a certain way to fit in the context of the view type.

The view selects a component based on the resource's class or renders a default view when there is no component for that class. In this example, we have a ResourceInline view that renders a resource inline in some text. For most resources, it will just render the name but for a Person or Product, it will render a special component.

// views/inline/ResourceInline.tsx

import { useResource } from '@tomic/react';
import { shop } from '../../ontologies/shop'; // <-- Generated with @tomic/cli
import { PersonInline } from './PersonInline';
import { ProductInline } from './ProductInline';

interface ResourceInlineProps {
  subject: string;
}

export interface ResourceInlineViewProps<T> {
  resource: Resource<T>;
}

export const ResourceInline = ({ subject }: ResourceInlineProps): JSX.Element => {
  const resource = useResource(subject);

  const Comp = resource.matchClass({
    [shop.classes.product]: ProductInline,
    [shop.classes.person]: PersonInline,
  }, Default);

  return <Comp subject={subject} />
}

const Default = ({ subject }: ResourceInlineViewProps<unknown>) => {
  const resource = useResource(subject);

  return <span>{resource.title}</span>
}

The PersonInline view will render a person resource inline. It could render a mention-like thing with the person's name, their profile picture and a link to their profile for example.

// views/inline/PersonInline.tsx
import { useResource, Resource, type Server } from '@tomic/react';
import type { Person } from '../../ontologies/social' // <-- Generated with @tomic/cli
import type { ResourceInlineViewProps } from './ResourceInline';

export const PersonInline = ({ resource }: ResourceInlineViewProps<Person>) => {
  const image = useResource<Server.File>(resource.props.image);

  return (
    <span className="person-inline">
      <img src={image.props.downloadUrl} className="profile-image-inline" />
      <span>{resource.title}</span>
    </span>
  )
}