Skip to content

Instantly share code, notes, and snippets.

@spro
Last active January 7, 2024 16:22
Show Gist options
  • Star 21 You must be signed in to star a gist
  • Fork 7 You must be signed in to fork a gist
  • Save spro/a4ccb681ba05abde9943fdfcd9bf497d to your computer and use it in GitHub Desktop.
Save spro/a4ccb681ba05abde9943fdfcd9bf497d to your computer and use it in GitHub Desktop.
Attempt at SSR with Recoil - setting initial atom values with Next.js getServerSideProps
import {useEffect} from 'react'
import {RecoilRoot, useRecoilState, atom} from 'recoil'
// User data
const user1 = {username: 'joe', bio: "You will never see me, unless of course this example is totally broken."}
const user2 = {username: 'bob', bio: "I am the one true user."}
const user3 = {username: 'fred', bio: "Just kidding, make way for the new guy."}
// Recoil atom to store user. The default user is user1, but it will be
// replaced when the root state is initialized
const userState = atom({
key: 'user',
default: user1
})
// Keep a reference to all atoms by key for initializeRecoilState
const all_atoms = {
user: userState
}
// Where the magic happens: Used by RecoilRoot to update atoms by key given an
// initial state object of the form {key: initial_value}
const initializeRecoilState = (initialRecoilState) => ({set}) =>
Object.keys(initialRecoilState).map((key) => {
const value = initialRecoilState[key]
const atom = all_atoms[key]
set(atom, value)
})
// Component to display user info
function User() {
const [user, setUser] = useRecoilState(userState)
// Show recoil is alive by setting to user3 after a bit
useEffect(() =>
setTimeout(() => setUser(user3), 2000)
, [])
return <div>
<strong className='username'>{user.username}</strong>
<p className='bio'>{user.bio}</p>
</div>
}
// Faux SSR "loading" user2 into the initial state
export async function getServerSideProps() {
const initialRecoilState = {
user: user2
}
console.log("Created initial Recoil state:", initialRecoilState)
return {
props: {initialRecoilState}
}
}
export default function Home({initialRecoilState={}}) {
console.log('Rendering with initial Recoil state:', initialRecoilState)
return (
<RecoilRoot initializeState={initializeRecoilState(initialRecoilState)}>
<User />
</RecoilRoot>
)
}
@kesavamuthu
Copy link

kesavamuthu commented Apr 6, 2023

It'll work for atom family ? @spro

@kesavamuthu
Copy link

const editorAtomFam = atomFamily({
key: "editor",
default: (params) => new DefaultValue({ content: params }),
});

function getServerSideProps(ctx) {
editorAtomFam("init").default = new DefaultValue({
content: "articles.openingContent",
});

}

I've used this solution to set default values but it's not working the atom is undefined always.

@jgsheppa
Copy link

@kesavamuthu You cannot set Recoil state on the server. Why do you need an atomFamily for that particular case? It looks like you could pass you data to an atom and then manipulate it with a selector or selectorFamily.

@gmalnk
Copy link

gmalnk commented Jan 7, 2024

"use client" is required when we import Recoil Root. getServerSideProps does not work (not get called) in the client component. then how are we supposed to initialize a recoil atom to a prop provided by getServerSideProps function.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment