Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

promise from useAsync not behaving as expected #250

Open
peterlenagh opened this issue Jan 27, 2020 · 3 comments
Open

promise from useAsync not behaving as expected #250

peterlenagh opened this issue Jan 27, 2020 · 3 comments

Comments

@peterlenagh
Copy link

peterlenagh commented Jan 27, 2020

Hi!

I'm trying to use react-async with redux-form.

Redux form wants the submit fn to return a promise.

I've tried using run & promise from useAsync but I can't get it to work, am I missing something?

minimal example:

https://codesandbox.io/embed/redux-form-react-async-submissionerror-example-91vcf

Thanks for your time!

@ghengeveld
Copy link
Member

It's very hard to debug this kind of thing, especially because I have no idea what redux form is doing under the hood to optimize renders.

The problem is that in your onSubmit, the value of promise is still an old promise. It isn't updated until the next render, which happens when the promise resolves or rejects. The initial value of promise is a fake promise which never settles, so chaining on it won't do anything.

You can verify by using useEffect:

React.useEffect(() => {
  console.log('useEffect')
  promise.then(console.log, console.error) // this will log the error after 1s
}, [promise])

One solution that I've seen is to keep a reference to the promise in local state or a ref and update it through useEffect. However this is fragile so it might not be worth the trouble. Exposing references to the underlying promise from React Async has been a topic of debate. In the past, run returned a promise, which is what would've probably worked here. However this caused a memory leak because you'd be assigning callbacks to promises that would never settle, so those functions would stay around forever. It's a tricky situation and we still haven't found a solution that works well everywhere.

@peterlenagh
Copy link
Author

peterlenagh commented Jan 31, 2020

Thanks for replying @ghengeveld!

OK, so it sounds like the 'access the underlying promise' stuff isn't really on the happy path. I suppose it sort of runs counter to the purpose of the library anyway.

My solution here, for anyone who is trying to integrate w/ redux form, was to use react-async without directly accessing the promise & just dispatch redux form actions for startSubmit/stopSubmit (not by throwing SubmissionErrors).

e.g.

const deferFn = ([values]) => {
  // this would be a fetch/post
  return new Promise((res, rej) => {
+    setTimeout(res({type: 'error', errors: { field1: "woops?" }}), 1000);
-    setTimeout(res), 1000);
-  }).then(() => {
-    throw new SubmissionError({ field1: "woops?" });
  });
};

...

const { run, data: response, promise } = useAsync(deferFn);

const onSubmit = () => {
	run();
-	return promise;
+	dispatch(startSubmit('formname'));
}

+// listen to response to dispatch errors
+useEffect(() => {
+	if (!response.type === 'error') return;
+	dispatch(stopSubmit('formname', response.errors));
+},[response])

@ghengeveld
Copy link
Member

Good to know you found a reasonable workaround. I'm not thrilled that it has to be done this way though, so it's high on the wishlist for future improvements.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants