T
TanStack2mo ago
probable-pink

How to get a final type of my form for use in a global store

Hi all, I'm using Solid and I'm seeing if I can store my form in a global context so that I don't have to prop drill it everywhere I need it. But this would mean creating the form itself outside of my main app component which means I'm not sure how to type my form. Also I'm using Form Composition. Basically is there a way to get the type of the final FormApi after I've declared my defaultValues and onSubmit and whatnot? This is what I currently have, not even sure if this is the best idea but I just don't want to have to prop drill my form everywhere I need it
// StoreProvider.tsx
export const {
fieldContext,
useFieldContext,
formContext,
useFormContext,
} = createFormHookContexts()

export const { useAppForm, withForm } = createFormHook({
fieldContext,
formContext,
fieldComponents: {...},
formComponents: {...},
})

type Form = ReturnType<typeof useAppForm> // ⚠️ This is the bit I'm not sure about. Ideally I'd like this to be the final type of the value of `useAppForm`

interface StoreProps {
form: Form,
}

type Props = ParentProps<StoreProps>

interface StoreContextValue {
store: StoreProps,
setStore: SetStoreFunction<StoreProps>
}

export const StoreContext = createContext<StoreContextValue>()

export function StoreProvider({
children,
}: Props) {
const form = useAppForm(() => ({
defaultValues: {
sections: {} as Record<string, Section>,
options: {} as Record<string, Option>,
},
onSubmit: ({ value }) => {
console.log(value)
}
}))

const [store, setStore] = createStore<StoreProps>({
form,
})

return (
<StoreContext.Provider value={{ store, setStore }}>
{children}
</StoreContext.Provider>
)
}
// StoreProvider.tsx
export const {
fieldContext,
useFieldContext,
formContext,
useFormContext,
} = createFormHookContexts()

export const { useAppForm, withForm } = createFormHook({
fieldContext,
formContext,
fieldComponents: {...},
formComponents: {...},
})

type Form = ReturnType<typeof useAppForm> // ⚠️ This is the bit I'm not sure about. Ideally I'd like this to be the final type of the value of `useAppForm`

interface StoreProps {
form: Form,
}

type Props = ParentProps<StoreProps>

interface StoreContextValue {
store: StoreProps,
setStore: SetStoreFunction<StoreProps>
}

export const StoreContext = createContext<StoreContextValue>()

export function StoreProvider({
children,
}: Props) {
const form = useAppForm(() => ({
defaultValues: {
sections: {} as Record<string, Section>,
options: {} as Record<string, Option>,
},
onSubmit: ({ value }) => {
console.log(value)
}
}))

const [store, setStore] = createStore<StoreProps>({
form,
})

return (
<StoreContext.Provider value={{ store, setStore }}>
{children}
</StoreContext.Provider>
)
}
2 Replies
fair-rose
fair-rose2mo ago
Hey, hope you're good. Is the idea that you use this to create other forms? I am just trying to understand the goal so I can see if I can help 😁
probable-pink
probable-pinkOP2mo ago
Heyo, no so the idea is that I have a very big dynamic form but not each of the sections of my form map 1-1 with the fields in the form object itself. So I need to read form data from various places which aren't strictly form controls. So I'd like to have the form object in context so I don't need to prop drill it everywhere I need it because there's quite a few layers in my application So I actually did find a little workaround, I'm not the biggest fan of this, but it ok for me for now. So I can get the return type of a function which returns a new instance of a form object
function createForm() {
return useAppForm(() => ({
defaultValues: {
foo: {},
bar: {},
},
onSubmit: (state) => {},
}))
}

type Form = ReturnType<typeof createForm>
function createForm() {
return useAppForm(() => ({
defaultValues: {
foo: {},
bar: {},
},
onSubmit: (state) => {},
}))
}

type Form = ReturnType<typeof createForm>
Now Form has the correct type and I can use that as a type in my context object
import { createContext } from "solid-js"

interface StoreContext {
form: Form,
}

const storeContext = createContext<StoreContext>()
import { createContext } from "solid-js"

interface StoreContext {
form: Form,
}

const storeContext = createContext<StoreContext>()

Did you find this page helpful?