Quick Start

Requirements

  • ES6+
  • React 18+

Installation

Install pinia-react with your preferred package manager:

npm
yarn
pnpm
bun
npm install pinia-react

Initialize Pinia

This example uses the browser entry point of an existing React project, with an element whose id is app in the HTML. Call createPinia() once before rendering the application to initialize the state container used by Stores. For Next.js App Router, use the root Provider setup in the Next.js guide.

TSX
JSX
src/index.tsx
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import { App } from './App'
import { createPinia } from 'pinia-react'

createPinia()

const container = document.querySelector('#app')
if (!container) throw new Error('Missing #app root element')

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

Define a Store

A Store groups shared state, derived values (Getters), and methods that change state (Actions). Define a counter in src/stores/counter.ts:

src/stores/counter.ts
import { defineStore } from 'pinia-react'

export const { useCounterStore, getCounterStore } = defineStore('counter', {
  state: () => {
    return { count: 0 }
  },
  getters: {
    double: state => state.count * 2,
  },
  actions: {
    increment() {
      this.count++
    },
  },
})

defineStore('counter', ...) generates useCounterStore and getCounterStore. Use the Hook in components and the plain getCounterStore() function outside them. See using Stores outside components.

Use the Store in a component

In src/App.tsx, read count and change it through an Action:

src/App.tsx
import { useCounterStore } from './stores/counter'

export function App() {
  const counter = useCounterStore()

  return (
    <div>
      <p>Current Count: {counter.count}; double: {counter.double}</p>
      <button onClick={() => counter.increment()}>Increment</button>
    </div>
  )
}

Start your project's development server and click “Increment”; the count should change from 0 to 1. Public Store state is read-only: do not call counter.count++ directly in a component.

For a JSX project, use the same Store and component code in .js and .jsx files.

Continue with State, Getters, and Actions for type inference, derived values, and asynchronous changes.

For independently mounted roots, requests and final teardown, see instance ownership and disposal. disposePinia is an explicit, irreversible owner operation, not an Effect cleanup; Provider unmount does not dispose automatically.