Skip to content
D
Documentation

React quick start

tutorial
2 min readUpdated

Build a typed React counter that selects state and calls a store action without a provider.

Your store is a hook: create it with state and actions, then select what each component needs.

Prerequisites

Use an existing browser-based React TypeScript project with:

  • React 18 or later, with react-dom for rendering.
  • React types (@types/react) 18 or later and the corresponding React DOM types.
  • TypeScript 4.5 or later.
  • Node.js 12.20.0 or later, as required by Zustand's package; your project's tooling can require a newer version.

These examples use the React JSX transform and a bundler that loads a TypeScript entry point from HTML.

Install Zustand

Install the zustand package in your project:

bash
npm install zustand

1. Create a typed store

Use create with the curried TypeScript form, create<CounterState>()(…). Define your application's state and action together. The returned useCounterStore is the hook your components call.

ts
import { create } from 'zustand'

type CounterState = {
  count: number
  increment: () => void
}

export const useCounterStore = create<CounterState>()((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
}))

The store starts with count set to 0. The functional update reads the current count and adds one. set merges the returned object into the state, so updating count keeps the increment action.

2. Select state and actions in components

Call the store hook with a selector. Counter receives the selected number; Controls receives the action function and passes it to the button's onClick handler.

tsx
import { useCounterStore } from './store'

function Counter() {
  const count = useCounterStore((state) => state.count)
  return <h1>Count: {count}</h1>
}

function Controls() {
  const increment = useCounterStore((state) => state.increment)
  return <button onClick={increment}>+1</button>
}

export default function App() {
  return (
    <main style={{ minHeight: 200, padding: 24 }}>
      <Counter />
      <Controls />
    </main>
  )
}

Both components use the same store without a Zustand provider. When count changes, Counter re-renders with the new value. Each selector subscribes its component to the value it returns rather than the entire state.

3. Mount the counter

Give React a root element and load your entry point. In your project's HTML, use:

html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Zustand counter</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>

Render App into that element:

tsx
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import App from './App'

const container = document.getElementById('root')!

createRoot(container).render(
  <StrictMode>
    <App />
  </StrictMode>,
)

Start your project's development server and open its browser URL. You see Count: 0 and a +1 button. Click +1: the heading changes to Count: 1. Each subsequent click increases the displayed count by one.

You now have a typed store with colocated state and an action, two selector-based components, and a mounted counter without a provider. See the live Zustand demo for another counter example.

Where to go next

Was this page helpful?