react-async: `promise` is undefined until first load/run
In Version 8 the run method no longer returns a promise. Instead the promise prop should be used. However, when using useFetch, the promise property is undefined.
Here is a test that demonstrates this:
test("defer=true allows using the promise", () => {
let check = 0
const component = (
<Fetch input="/test" options={{ defer: true }}>
{({ run, promise }) => (
<button
onClick={() => {
run()
promise
.then(() => {
return (check = 1)
})
.catch(() => {})
}}
>
run
</button>
)}
</Fetch>
)
const { getByText } = render(component)
fireEvent.click(getByText("run"))
expect(check).toEqual(1)
})
I’ll also add a Pull-Request with these failing tests.
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Comments: 20 (16 by maintainers)
@bogdansoare I feel your pain. I’m actually inclined to restore the chainability of
runby returning a Thenable (PromiseLike) from it. Because it’s not an actual Promise it avoids theuncaught exceptionissue (althoughawaitwill still throw on rejection because it treats the Thenable as a Promise). However I think we should be careful not to regress in previously resolved problems. It’s clear that thepromiseprop is causing more harm than good.also having this issue,
runshould return a promisemy use case is having to perform an action after the run completes, for a concrete example I have a form inside a modal dialog and I want to close the modal when the run completes
I’ve decided to just fix the issue at hand (promise being undefined), and care about the repercussions later. I’ve simply added a warning to the readme that you have to specify a rejection handler when chaining on
promise.As for the ongoing discussion, let’s take that into account while designing the future version of React Async / Async Library. One idea I have right now is to introduce a
thenprop which is synonymous topromise.then, but specifies a default value for onReject, so it will always be defined even if you forget to provide it yourself. Essentially this:I think the puzzle piece missing here is to be able to pass something to onResolve when calling run. At least, that would be great for my example in #75, where
actions.setSubmittingis only available within the callback (that promise was very useful there)Yes, thanks for that. I’ve reviewed your PR and given it some thought. I now think
promiseshould not beundefinedat the first render. Instead it should always be a Promise. We can do that by setting the initial value ofpromiseto a Promise that never resolves or rejects. Then oncerun()is invoked we replace it with the actual underlying promise (which should eventually resolve or reject).