Next.js and Jotai: Share state across pages

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

--

--

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