I am trying to create a button that I can put anywhere on a page to submit a specific form. I'm interested in using Hooks and Context / Provider pattern to expose this state anywhere in the app.
The code below creates a context / provider that has access to a useState hook for setting the submit function.
import React from 'react';
import {createContext, ReactNode, useContext, useEffect, useRef, useState} from 'react';
export type HiddenButtonSubmitContext = {
submit: () => void,
setSubmitHandler: React.Dispatch<React.SetStateAction<() => void>>
}
export const defaultSetSubmitHandler = () => () => {
// eslint-disable-next-line no-console
console.log('submit handler was never set')
}
export const SubmitContext = createContext<HiddenButtonSubmitContext>({
submit: () => {
throw new Error('submit not set, make surea all calls to useHiddenButton are within HiddenButtonProvider');
},
setSubmitHandler: defaultSetSubmitHandler()
})
export const useHiddenButton = () => useContext(SubmitContext)
export const HiddenButtonProvider: React.FC<{ children?: ReactNode | undefined }> = ({ children }) => {
const [submit, setSubmitHandler] = useState(defaultSetSubmitHandler)
return (
<SubmitContext.Provider value={{submit, setSubmitHandler}}>
{children}
</SubmitContext.Provider>
)
}
export const HiddenButton = () => {
const hiddenButtonRef = useRef<any>()
const { setSubmitHandler } = useHiddenButton()
useEffect(() => {
setSubmitHandler(() => () => {
hiddenButtonRef.current.click()
})
}, [setSubmitHandler])
return (
<input type="submit" style={{ display: 'none' }} ref={hiddenButtonRef} />
)
}
Here's the example usage:
const Btn = () => {
const { submit } = useHiddenButton()
return <button onClick={() => submit()}>hi</button>
}
export function Example () {
return (
<HiddenButtonProvider>
<Btn />
<form onSubmit={(e) => {
e.preventDefault()
console.log('submitted')
}}>
<HiddenButton/>
</form>
</HiddenButtonProvider>
)
}