@just-web/react
TypeScript icon, indicating that this package has built-in type declarations

9.0.4 • Public • Published

@just-web/react

NPM version NPM downloads

@just-web/react provides the features needed to use just-web app with React.

Install

# npm
npm install @just-web/react

# yarn
yarn add @just-web/react

# pnpm
pnpm install @just-web/react

#rush
rush add -p @just-web/react

Usage

We will be focusing on how to use just-web app with React here.

If you want to know more about just-web app, you can check out the documentation of @just-web/app.

Following the example from @just-web/app, let's make the sing-along app into a React app.

Let's start with a simple example: a SPA.

To create a React SPA, you need two things from @just-web/react:

  • <JustAppProvider/>: the React context provider for JustApp.
  • useJustAppContext(): the React context hook to get the JustApp instance.
import { JustAppProvider } from '@just-web/react'
import ReactDOM from 'react-dom'
import { YourComponent } from './your_component'
import { singAlongApp } from './sing_along_app'

void (async () => {
  const app = await singAlongApp.with(reactGizmo).create()

  ReactDOM.render(
    <JustAppProvider value={app}>
      <YourComponent />
    </JustAppProvider>,
    document.getElementById('root')
  )
})()

// your_component.tsx
import { useJustAppContext } from '@just-web/react'
import type { SingAlongApp } from './sing_along_app'

export function YourComponent() {
  const app = useJustAppContext<SingAlongApp>()

  return (
    <div>
      <MusicPlayer start={() => app.miku.sing()} />
    </div>
  )
}

For Micro Frontends (MFEs), just JustAppProvider and useJustAppContext() may not be sufficient. Especially if you have components from different MFEs intertwined together.

In that case, you will also need:

  • createJustAppContext(): to create a React context for each MFE.
  • reactGizmo: to register the specific React context for each MFE.

In the example below, we have two MFEs: miku and rin.

Each of them is a MFE with its own JustApp instance.

They need to add reactGizmo, and register their own React context.

They are doing it differently to show two different ways of doing it.

const MikuAppContext = createJustAppContext<MikuApp>()
const mikuApp = await singAlongApp.with(reactGizmo)
  .create(app => app.react.providers.register(({ children }) => (
    <MikuAppContext.Provider value={app}>
      {children}
    </MikuAppContext.Provider>
  )))

const RinAppContext = createJustAppContext<RinApp>()
const rinAppIncubator = singAlongApp.with(reactGizmo)
  .init(app => app.react.providers.register(({ children }) => (
    <RinAppContext.Provider value={app}>
      {children}
    </RinAppContext.Provider>
  )))
const rinApp = await rinAppIncubator.create()

Then, in the React app, you can use the JustAppProvider for both mikuApp and rinApp, and they will work together.

ReactDOM.render(
  <JustAppProvider value={mikuApp}>
    <MikuSinging />
    <JustAppProvider value={rinApp}>
      <MikuDancing />
      <RinSinging />
    </JustAppProvider>
  </JustAppProvider>,
  document.getElementById('root')
)

Inside your components, you can still use useJustAppContext() with the JustAppContext you have created to get your specific app.

import { useJustAppContext } from '@just-web/react'
import { MikuAppContext } from './miku_app'

export function MikuSinging() {
  const app = useJustAppContext(MikuAppContext)

  return (
    <div>
      <MusicPlayer start={() => app.miku.sing()} />
    </div>
  )
}

Alternatively, you can use <MikuAppContext.Provider> or <RinAppContext.Provider> too, but typically there is no need to do so. In fact, you can keep them off your package exports.

The host app only need the mikuApp, rinApp, and the JustAppProvider and everything will work.

useStore

useStore() Allows you to use store from @just-web/states.

It is similar to useState() in React, but work on a store instead of a local state.

import { createStore } from '@just-web/states'
import { useStore } from '@just-web/react'

const store = createStore({ counter: 0 })

const Component = () => {
  const [counter, setCounter] = useStore(
    store,
    // get which part of the store to use as state
    s => s.counter,
    // updateStore when state changes
    s=>{ s.counter = counter }
  )

  return <div>{counter}</div>
}

useStoreContext

useStore() is useful to consume an app-level store:

// from another file
import { store } from './store'

// or create at the module scope
const store = createStore(...)

const Component = () => {
  const [] = useStore(store, ...)
}

But it doesn't work well if we want to have a local store that live and die with the DOM.

In React, that's when you can use createContext() and useContext().

Here, we can use createStoreContext() and useStoreContext() to achieve the same thing with Store.

And the usage is much simpler and efficient thanks to the underlying immer implementation.

import { createStoreContext, useStoreContext } from '@just-web/react'
import { createStore } from '@just-web/states'

type YourStore = { counter: number }

const YourContext = createStoreContext<YourStore>() // no default value

const YourProvider = (props) => {
  const store = createStore<YourStore>({ counter: 0 })
  return <YourContext.Provider value={store} {...props}/>
}

const YourConsumer = () => {
  const [counter, setCounter] = useStoreContext(
    YourContext,
    s => s.counter,
    (s, v) => { s.counter = v }
  )

  return (
    <>
      <div>counter: {counter}</div>
      <button onClick={() => setCounter(counter + 1)}>Increment</button>
    </>
  )
}

reactGizmo

As seen in the example above, reactGizmo provides a react.providers where you can register React context providers.

You can use it to add other providers to the app.

For example, i18n, theme, etc.

import { createApp } from '@just-web/app'
import reactPlugin, { AppContextProvider } from '@just-web/react'

function YourApp() {
  const app = createApp({...}).extned(reactPlugin)
  app.react.providers.register(({ children }) => <YourProvider {...}>{children}</YourProvider>)

  return (
    <JustAppProvider value={app}>
      ...
    </JustAppProvider>
  )
}

The providers will be added to the app in the order they are registered, inside the <JustAppProvider>.

This allows any gizmo to add their needed providers to the app, without having the app to know about them.

Package Sidebar

Install

npm i @just-web/react

Weekly Downloads

3

Version

9.0.4

License

MIT

Unpacked Size

133 kB

Total Files

136

Last publish

Collaborators

  • unional