Next.js and Jotai: Share state across pages

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

Markus Tripp
4 min readSep 5, 2022

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:

--

--

Markus Tripp
Markus Tripp

Written by Markus Tripp

I ❤️ Shopify, Laravel, Next.js.

Responses (1)