Next.js and Jotai: Share state across pages
Simple yet powerful state management for your Next.js app.
When creating a Next.js application, there are often situations where you want to share data (or state) across several pages. Some examples are:
- 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.
You can use React’s Context to pass data through the component tree. Or choose one of the many state managers available.
In this article, I show you how to get started with Jotai, a very efficient and simple-to-use option. Therefore, I created a simplified e-commerce app that consists of 3 pages:
- Home
- Product
- Cart
On the product page, you can add an item to the cart. Now you want to share the cart ID and the total number of items in an object shared across all pages.
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 }
Then you can use your atoms similar to React state. But across several components and pages.
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.
Create Next.js app
npx create-next-app@latest
Add Jotai dependency
npm install jotai
I usually store my atoms in a single atoms.js file in the lib directory for smaller applications.
File: ./lib/atoms.js
--------------------import { atom } from 'jotai'const cartAtom = atom({
id: null,
quantity: 0,
})export { cartAtom }
The top navigation on every page contains links to all pages (home, product, cart) and the number of items in the cart. I extracted the functionality in a Nav.js component.
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
The individual pages are very simple. Here for instance the home page.
File: ./pages/index.js
----------------------import Nav from '../components/Nav'const Home = () => {
return (
<>
<Nav />
<h1>Example Online Shop</h1>
</>
)
}export default Home
If the user clicks “add to cart” on the product page the app updates the cartAtom with the new quantity and optionally creates a new cart.id.
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
This is a very simplified version. Usually you call an API from a headless e-commerce service to create or update the cart (e.g., Shopify headless frontend), and update the cart ID you receive via the callback.
Find the source code for this demo Next.js application using Jotai state management at github.com/markustripp/jotai-demo
About the author (Markus Tripp):
I’m a freelance web developer and Shopify consultant — and I’m the creator of Headcode CMS (www.headcodecms.com), a 100% open-source headless CMS for Next.js 13 App Router, Server Components, and Server Actions. Watch the video below for a quick product demo: