Next.js and Jotai: Share state across pages

Simple yet powerful state management for your Next.js app.

  • On an e-commerce site, this can be the cart ID or the number of items in the basket you want to share across your Next.js pages.
  • On an app, this can be the user’s name or email address you want to display on several pages.
  • Home
  • Product
  • Cart

Quick Answer

In short, you need a file to store your atoms.

File: ./lib/atoms.js
--------------------
import { atom } from 'jotai'const cartAtom = atom({
id: null,
quantity: 0,
})
export { cartAtom }
File: SomeComponent.js
----------------------
import { useAtom } from 'jotai'
import { cartAtom } from '../lib/atoms'
...
const SomeComponent = () => {
const [cart, setCart] = useAtom(cartAtom)
...
const handleSomeAction = () => {
...
const newCart = { id: 123, quantity: 1 }
setCart(newCart)
...
}
return (
...
{cart.quantity}
...
)
}
export default SomeComponent

Long Answer

To get started, create a new Next.js app and add Jotai as a dependency.

npx create-next-app@latest
npm install jotai
File: ./lib/atoms.js
--------------------
import { atom } from 'jotai'const cartAtom = atom({
id: null,
quantity: 0,
})
export { cartAtom }
File: ./components/Nav.js
-------------------------
import Link from 'next/link'
import { useAtom } from 'jotai'
import { cartAtom } from '../lib/atoms'
const links = [
{ path: '/', title: 'Home' },
{ path: '/product', title: 'Product' },
{ path: '/cart', title: 'Cart' },
]
const Nav = () => {
const [cart] = useAtom(cartAtom)
return (
<ul>
{links.map((link, index) => (
<li key={index}>
<Link href={link.path}>
<a>{link.title}</a>
</Link>
</li>
))}
<li>{cart.quantity} item(s) in cart</li>
</ul>
)
}
export default Nav
File: ./pages/index.js
----------------------
import Nav from '../components/Nav'const Home = () => {
return (
<>
<Nav />
<h1>Example Online Shop</h1>
</>
)
}
export default Home
File: ./pages/product.js
------------------------
import { useRouter } from 'next/router'
import { useAtom } from 'jotai'
import { cartAtom } from '../lib/atoms'

import Nav from '../components/Nav'
const Product = () => {
const router = useRouter()
const [cart, setCart] = useAtom(cartAtom)
return (
<>
<Nav />
<h1>Product XY</h1>
<p>
<button
onClick={() => {
setCart(
cart.id
? { ...cart, quantity: cart.quantity + 1 }
: { id: 123, quantity: cart.quantity + 1 }
)
router.push('/cart')
}}

>
<a>Add to cart</a>
</button>
</p>
</>
)
}
export default Product

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store