TinyBase logoTinyBase β

Building A UI With Metrics

This guide covers how the ui-react module supports the Metrics object.

As with the React-based bindings to a Store object, the ui-react module provides both hooks and components to connect your metrics to your interface.

Metrics Hooks

The useMetric hook is very simple. It gets the current value of a Metric, and registers a listener so that any changes to that result will cause a re-render:

import React from 'react';
import {createRoot} from 'react-dom/client';
import {createMetrics, createStore} from 'tinybase';
import {useMetric} from 'tinybase/ui-react';

const store = createStore().setTable('species', {
  dog: {price: 5},
  cat: {price: 4},
  worm: {price: 1},
});
const metrics = createMetrics(store);
metrics.setMetricDefinition('highestPrice', 'species', 'max', 'price');
const App = () => <span>{useMetric('highestPrice', metrics)}</span>;

const app = document.createElement('div');
const root = createRoot(app);
root.render(<App />);
console.log(app.innerHTML);
// -> '<span>5</span>'

store.setCell('species', 'horse', 'price', 20);
console.log(app.innerHTML);
// -> '<span>20</span>'

The useCreateMetrics hook is used to create a Metrics object within a React application with convenient memoization:

import {useCreateMetrics, useCreateStore} from 'tinybase/ui-react';

const App2 = () => {
  const store = useCreateStore(() =>
    createStore().setTable('species', {
      dog: {price: 5},
      cat: {price: 4},
      worm: {price: 1},
    }),
  );
  const metrics = useCreateMetrics(store, (store) =>
    createMetrics(store).setMetricDefinition(
      'highestPrice',
      'species',
      'max',
      'price',
    ),
  );
  return <span>{metrics?.getMetric('highestPrice')}</span>;
};

root.render(<App2 />);
console.log(app.innerHTML);
// -> '<span>5</span>'

Metrics View

The MetricView component renders the current value of a Metric, and registers a listener so that any changes to that result will cause a re-render.

import {MetricView} from 'tinybase/ui-react';

const App3 = () => (
  <div>
    <MetricView metricId="highestPrice" metrics={metrics} />
  </div>
);

root.render(<App3 />);
console.log(app.innerHTML);
// -> '<div>20</div>'

Metrics Context

In the same way that a Store can be passed into a Provider component context and used throughout the app, a Metrics object can also be provided to be used by default:

import {Provider} from 'tinybase/ui-react';

const App4 = () => {
  const store = useCreateStore(() =>
    createStore().setTable('species', {
      dog: {price: 5},
      cat: {price: 4},
      worm: {price: 1},
    }),
  );
  const metrics = useCreateMetrics(store, (store) =>
    createMetrics(store).setMetricDefinition(
      'highestPrice',
      'species',
      'max',
      'price',
    ),
  );

  return (
    <Provider metrics={metrics}>
      <Pane />
    </Provider>
  );
};

const Pane = () => (
  <span>
    <MetricView metricId="highestPrice" />,{useMetric('highestPrice')}
  </span>
);

root.render(<App4 />);
console.log(app.innerHTML);
// -> '<span>5,5</span>'

The metricsById prop can be used in the same way that the storesById prop is, to let you reference multiple Metrics objects by Id.

Solid And Svelte

The ui-solid and ui-svelte modules expose the same Metrics concepts using each framework's native reactive style. In Solid, the useMetric primitive returns an Accessor, and MetricView renders the same result as a component:

import {createRoot as createSolidMetricsRoot} from 'solid-js';
import {render as renderSolidMetrics} from 'solid-js/web';
import {createMetrics as createSolidMetrics} from 'tinybase';
import {createStore as createSolidMetricsStore} from 'tinybase';
import {
  MetricView as SolidMetricView,
  useMetric as useSolidMetric,
} from 'tinybase/ui-solid';

const solidMetricsStore = createSolidMetricsStore().setTable('species', {
  dog: {price: 5},
  cat: {price: 4},
});
const solidMetrics = createSolidMetrics(solidMetricsStore).setMetricDefinition(
  'highestPrice',
  'species',
  'max',
  'price',
);

createSolidMetricsRoot((dispose) => {
  const highestPrice = useSolidMetric('highestPrice', solidMetrics);
  console.log(highestPrice());
  // -> 5

  solidMetricsStore.setCell('species', 'horse', 'price', 20);
  console.log(highestPrice());
  // -> 20
  dispose();
});

const solidMetricsApp = document.createElement('div');
const disposeSolidMetrics = renderSolidMetrics(
  () => <SolidMetricView metricId="highestPrice" metrics={solidMetrics} />,
  solidMetricsApp,
);
console.log(solidMetricsApp.innerHTML);
// -> '20'
disposeSolidMetrics();

In Svelte, use the getMetric function for a reactive value, or MetricView for declarative rendering:

<script>
  import {getMetric, MetricView} from 'tinybase/ui-svelte';

  let {metrics} = $props();
  const highestPrice = getMetric('highestPrice', metrics);
</script>

<span>{highestPrice.current}</span>
<MetricView metricId="highestPrice" {metrics} />

Summary

The support for Metrics objects in the UI modules is very similar to that for the Store object, making it easy to attach Metric results to your user interface from React, Solid, or Svelte.

We finish off this section about the metrics module with the Advanced Metric Definition guide.