I'm trying to get into using react recoil for state management and I'm loving it so far, however at the moment I'm trying to integrate it with react-hook-form and I can't quite find a setup that works for me.
It's simple, I want to execute a function that uploads a file onSubmit after completing a Form. I've setup a selector to make an async request and update a corresponding atom with the upload progress, but I'm having trouble executing the function as it is getting called within a callback rather than a functional component, I've tried to extract it into a custom hook but that wasn't effective either; I've provided the code below, if anyone has any ideas let me know!
Example error of the current implementation:
React Hook "useRecoilValue" is called in function "submit" which is neither a React function component or a custom React Hook function
Code:
export const videoUploadProgressState = atom({
    key: "videoProgress",
    default: {progress: 0.0}
});
export const videoUploadState = selectorFamily({
    key: 'videoUploadState',
    get: (data : {[key:string] : any}) => async ({get}) => {
        const storage = get(firestoreStorageState);
        const task = storage.ref(data.path).put(data.file);
        const [progress, setProgress] = useRecoilState(videoUploadProgressState)
        task.on("state_changed", snapshot =>{
            switch(snapshot.state){
                case 'running':
                    setProgress({progress: snapshot.bytesTransferred / snapshot.bytesTransferred});
                    break;
                }
            }
        );
        const response = await fetch(
            "http://*********:80/streaming/create-video-asset",
            {
                method:'post', 
                body:JSON.stringify({url: (await task).ref.getDownloadURL()})
            });
        console.log(response.json());
        return response.json();
        
    }
})
const UploadMovieComponent = () => {
  const [title, setTitle] = useState("Select movie");
  const {register, handleSubmit} = useForm();
  const movies = useRecoilValue(movieState);
  const progress = useRecoilValue(videoUploadProgressState)
  const submit = (data) => {
    setTitle(
      useRecoilValue(
        videoUploadState(
          {
            path: `movies/${data.id}/${data.movieFile[0].name}`, 
            file: data.movieFile[0]
          }
        )
      )
    );
  }
  return(
    <div>
      <Form onSubmit={handleSubmit(submit)}>
  <Form.Group controlId="exampleForm.SelectCustom">
    <Form.Label>Select movie</Form.Label>
    <Form.Control as="select" ref={register} name="id" custom>
    {movies.map(movie=> <option value={movie.id}>{movie.title}</option>)}
    </Form.Control>
  </Form.Group>
  <Form.Group>
    <Form.File name="movieFile" ref={register}/>
  </Form.Group>
  <Button type="submit" variant="outline-warning">Upload</Button>
</Form>
<ProgressBar className="mt-2" now={progress.progress} />
    </div>
  );
}
 
                        
the solution involved using the
setproperty on the selector to pass in adataobject containing the parameters I want to sent to theurl.This way you can use the
useSetRecoilStatehook to obtain a callback that can be used outside the the scope of the component tree: