Skip to main content

React

Integrating superstate with React is easy.

First you have to install @superstate/react:

npm install @superstate/react

Then you'll be able to import the useSuperState hook:

import { superstate } from '@superstate/core'
import { useSuperState } from '@superstate/react'

const count = superstate(0)

export default function App() {
  useSuperState(count)

  return (
    <div>
      Count is <strong>{count.now()}</strong><br/>

      <button onClick={() => count.set(prev => prev - 1)}>-</button>
      <button onClick={() => count.set(prev => prev + 1)}>+</button>
    </div>
  )
}

Targeting specific state version

By default, the useSuperState hook will re-render your React component whenever either now or draft change. However, sometimes you want to monitor only changes made to the draft instead. To do so, all you have to do is specifying draft as a useSuperState target:

import { superstate } from '@superstate/core'
import { useSuperState } from '@superstate/react'

const count = superstate(0)

export default function App() {
  useSuperState(count, { target: 'draft' }) // this line!

  return (
    <div>
      <button onClick={() => count.sketch(prev => prev - 1)}>-</button>
      <button onClick={() => count.sketch(prev => prev + 1)}>+</button>

      {typeof count.draft() !== 'undefined' &&
        <section>
          Count's draft is: <strong>{count.draft()}</strong><br/>
        </section>
      }
    </div>
  )
}

If you want to target only now version instead of both now and draft, just pass now to target.

Smart re-renders

It may sound dangerous to always re-render your component whenever a state changes, but don't worryโ€”a re-render will only occur when changes are broadcasted, and changes are only broadcasted when the new state is actually different from the previous state.

Meaning that:

const count = superstate(0)
count.publish(5) // will trigger a re-render
count.publish(5) // will NOT trigger a re-render
count.publish(5) // will NOT trigger a re-render
count.publish(prev => prev) // will NOT trigger a re-render
count.publish(prev => prev + 1) // will trigger a re-render

const user = superstate({ name: 'John' })
user.publish(prev => prev) // will NOT trigger a re-render
user.publish(prev => ({ name: 'Doe' })) // will trigger a re-render

Currently, custom logic to trigger broadcasts/re-render is not supported.

Components rendering twice

If your component is rendering twice upon a superstate state change, it may be because of React's <StrictMode />. Just to make sure, unwrap your app from <StrictMode /> and try changing the state again.

If the problem went away, put your <StrictMode /> back and don't worryโ€”this doubled re-render is only happening in development mode and it's intentional (learn more); otherwise, file an issue on GitHub.