Skip to content

State Management

State Management in Frog looks a bit different to what you might be used to with client-side web frameworks such as: React, Vue, Svelte, etc. The critical difference is that Frog has no sense of "reactivity" and "interactivity" as it is purely server-side image rendering.

State Management in Frog is achieved through "state derivation", and we can use the deriveState function to derive new state based on the previous state.

Essentially, state = deriveState(previousState).

Here's an example of a simple counter:

/** @jsxImportSource frog/jsx */
// ---cut---
import { Button, Frog } from 'frog'
 
type State = {   
  count: number
}
 
export const app = new Frog<{ State: State }>({
  initialState: {
    count: 0
  }
})
 
app.frame('/', (c) => {
  const { buttonValue, deriveState } = c
  const state = deriveState(previousState => {
    if (buttonValue === 'inc') previousState.count++
    if (buttonValue === 'dec') previousState.count--
  })
  return c.res({
    image: (
      <div style={{ color: 'white', display: 'flex', fontSize: 60 }}>
        Count: {state.count}
      </div>
    ),
    intents: [
      <Button value="inc">Increment</Button>,
      <Button value="dec">Decrement</Button>,
    ]
  })
})
## Errors were thrown in the sample, but not included in an error tag These errors were not marked as being expected: 2345. Expected: // @errors: 2345 Compiler Errors: index.tsx [2345] 219 - Argument of type '{ initialState: { count: number; }; }' is not assignable to parameter of type 'FrogConstructorParameters<{ State: State; }, "/", State>'. Property 'title' is missing in type '{ initialState: { count: number; }; }' but required in type 'Required<Pick<FrameResponse, "title">>'.