JBrowse 2 · React App examples

Loading configuration

Import or fetch a config.json, or add tracks and views later.

On this page: Import a config.json · Fetch a config.json · Add tracks programmatically · Launch a view imperatively

Import a config.json

Bundled at build time.

URIs in a config.json are relative to where it was served, so addRelativeUris resolves them against that URL. The file’s shape is JBrowseRootConfig.

View source — 13 lines
import { addRelativeUris } from '@jbrowse/core/util/addRelativeUris'
import { JBrowseApp, useCreateViewState } from '@jbrowse/react-app2'

import config from '../volvox-config.json' with { type: 'json' }

const configUrl =
  'https://jbrowse.org/code/jb2/main/test_data/volvox/config.json'
addRelativeUris(config, new URL(configUrl))

export default function WithImportConfigJson() {
  const state = useCreateViewState({ config })
  return state ? <JBrowseApp viewState={state} /> : null
}

Fetch a config.json

Fetched at runtime.

Unlike JBrowse Web, the embedded app does not load a config’s plugins: hand them to loadPlugins, whose baseUri resolves a relative plugin URL against the config rather than your page.

View source — 48 lines
import { useEffect, useState } from 'react'

import { addRelativeUris } from '@jbrowse/core/util/addRelativeUris'
import {
  JBrowseApp,
  createViewState,
  destroyViewState,
  loadPlugins,
} from '@jbrowse/react-app2'

type ViewState = ReturnType<typeof createViewState>

const configUrl =
  'https://jbrowse.org/code/jb2/main/test_data/volvox/config.json'

export default function WithFetchConfigJson() {
  const [state, setState] = useState<ViewState>()
  useEffect(() => {
    const mount = {
      unmounted: false,
      engine: undefined as ViewState | undefined,
    }
    void (async () => {
      const response = await fetch(configUrl)
      if (!response.ok) {
        throw new Error(`HTTP ${response.status} fetching config ${configUrl}`)
      }
      const config = await response.json()
      addRelativeUris(config, new URL(configUrl))
      const plugins = await loadPlugins(config.plugins ?? [], {
        baseUri: configUrl,
      })
      if (mount.unmounted) {
        return
      }
      mount.engine = createViewState({ config, plugins })
      setState(mount.engine)
    })()
    return () => {
      mount.unmounted = true
      if (mount.engine) {
        destroyViewState(mount.engine)
      }
    }
  }, [])

  return state ? <JBrowseApp viewState={state} /> : null
}

Add tracks programmatically

addTrackConf, then launchTrack.

View source — 57 lines
import { useRef, useState } from 'react'

import { JBrowse } from '@jbrowse/react-app2'

import type { ViewModel } from '@jbrowse/react-app2'

const base = 'https://jbrowse.org/code/jb2/main/test_data/volvox'

const assemblies = [{ name: 'volvox', uri: `${base}/volvox.2bit` }]

const genesTrackConf = {
  type: 'FeatureTrack',
  trackId: 'volvox_genes',
  name: 'Volvox genes',
  assemblyNames: ['volvox'],
  adapter: { type: 'Gff3TabixAdapter', uri: `${base}/volvox.sort.gff3.gz` },
}

export default function AddTracksProgrammatically() {
  const ref = useRef<ViewModel>(null)
  const [added, setAdded] = useState(false)

  async function addTrack() {
    const state = ref.current
    if (state) {
      state.jbrowse.addTrackConf(genesTrackConf)
      await state.session.views[0]?.launchTrack('volvox_genes')
      setAdded(true)
    }
  }

  return (
    <div>
      <button
        disabled={added}
        onClick={() => {
          void addTrack()
        }}
      >
        {added ? 'Genes track added' : 'Add genes track'}
      </button>
      <JBrowse
        ref={ref}
        assemblies={assemblies}
        tracks={[]}
        sessionName="Programmatic tracks"
        views={[
          {
            type: 'LinearGenomeView',
            assembly: 'volvox',
            loc: 'ctgA:1..50000',
          },
        ]}
      />
    </div>
  )
}

Launch a view imperatively

The LaunchView extension point, after mount.

LaunchView-LinearSyntenyView and LaunchView-DotplotView work the same way. Automating JBrowse describes the init they share.

View source — 80 lines
import { useEffect, useState } from 'react'

import { ErrorMessage } from '@jbrowse/core/ui'
import { getEnv } from '@jbrowse/core/util'
import {
  JBrowseApp,
  createViewState,
  destroyViewState,
} from '@jbrowse/react-app2'

type ViewState = ReturnType<typeof createViewState>

export default function WithLaunchLinearGenomeView() {
  const [viewState, setViewState] = useState<ViewState>()
  const [error, setError] = useState<unknown>()

  useEffect(() => {
    const mount = { engine: undefined as ViewState | undefined }
    void (async () => {
      try {
        const state = createViewState({
          config: {
            assemblies: [
              {
                name: 'GRCh38',
                aliases: ['hg38'],
                uri: 'https://jbrowse.org/genomes/GRCh38/fasta/hg38.prefix.fa.gz',
                refNameAliases: {
                  uri: 'https://s3.amazonaws.com/jbrowse.org/genomes/GRCh38/hg38_aliases.txt',
                },
                geneticCodes: { chrM: 2 },
              },
            ],
            tracks: [
              {
                type: 'QuantitativeTrack',
                trackId: 'hg38.100way.phyloP100way',
                name: 'hg38.100way.phyloP100way',
                category: ['Conservation'],
                assemblyNames: ['hg38'],
                adapter: {
                  type: 'BigWigAdapter',
                  uri: 'https://hgdownload.soe.ucsc.edu/goldenpath/hg38/phyloP100way/hg38.phyloP100way.bw',
                },
              },
            ],
          },
        })
        const { pluginManager } = getEnv(state)

        mount.engine = state
        setViewState(state)
        await pluginManager.evaluateAsyncExtensionPointStrict(
          'LaunchView-LinearGenomeView',
          {
            tracks: ['hg38.100way.phyloP100way'],
            loc: 'chr10:1-100000',
            assembly: 'hg38',
            session: state.session,
          },
        )
      } catch (e) {
        console.error(e)
        setError(e)
      }
    })()
    return () => {
      if (mount.engine) {
        destroyViewState(mount.engine)
      }
    }
  }, [])

  return viewState ? (
    <>
      {error ? <ErrorMessage error={error} /> : null}
      <JBrowseApp viewState={viewState} />
    </>
  ) : null
}