import { atom, useAtom } from 'jotai';
import { useAtomCallback } from 'jotai/utils';
import React, { createContext, useContext, useMemo } from 'react';
type FormState = { email: PrimitiveAtom<string>; password: PrimitiveAtom<string>; };
const FormStateContext = createContext<FormState | null>(null);
export function FormProvider({ children }: { children: React.ReactNode }) {
// Create atoms once
const formState = useMemo(() => ({ email: atom(''), password: atom('') }), []);
// Derived atom to get all values for submission
const payloadAtom = useMemo(() => atom((get) => {
return Object.fromEntries(Object.entries(formState).map(([k, v]) => [k, get(v)]));
}), [formState]);
// handleSubmit does not trigger re-renders of FormProvider
const handleSubmit = useAtomCallback((get, _, event) => {
event.preventDefault();
console.debug(get(payloadAtom));
}, [payloadAtom]);
return (
<FormStateContext.Provider value={formState}>
<Form onSubmit={handleSubmit}>{children}</Form>
</FormStateContext.Provider>
);
}
export function useFormFieldState(name: keyof FormState) {
const context = useContext(FormStateContext);
if (!context) throw new Error('Missing FormStateContext.Provider');
return useAtom(context[name]); // Only this component re-renders when this atom changes
}