Skip to content

bailout when hook throws an error#2193

Merged
JoviDeCroock merged 7 commits into
masterfrom
fix/effect-error
Jan 23, 2020
Merged

bailout when hook throws an error#2193
JoviDeCroock merged 7 commits into
masterfrom
fix/effect-error

Conversation

@JoviDeCroock

Copy link
Copy Markdown
Member

fixes: #2192

@coveralls

coveralls commented Dec 18, 2019

Copy link
Copy Markdown

Coverage Status

Coverage increased (+0.002%) to 99.807% when pulling 69cc710 on fix/effect-error into ec5340f on master.

Comment thread hooks/src/index.js
@tyler-graham-ck

tyler-graham-ck commented Dec 18, 2019

Copy link
Copy Markdown

oh snap, thanks, was gonna clone after lunch 😉

does it make sense to catch in _render, unmount, etc too?

@JoviDeCroock

JoviDeCroock commented Dec 18, 2019

Copy link
Copy Markdown
Member Author

No, those are part of the diffing algorithm it are only the ones scheduled for delayed execution that bypass diff and don't get picked up by the parentComponents.

Seems like I didn't press enter when commenting on your issue, sorry for that.

@tyler-graham-ck

Copy link
Copy Markdown

ahh. if you get a chance can you link to where that happens?

@JoviDeCroock

Copy link
Copy Markdown
Member Author

I can surely do so

For the first case we do a synchronous cleanup for the effects still pending for a component this can happen with many subsequent renders, here we use the _render option this is within the diffing loop so if a throw occurs it will catch it just as a normal throw in render would.

For the next case we have unmount, something that can only occur during diffing when we are diffing children and we see that one isn't there anymore we call unmount which links through to the option we are still in our diffing loop since diffChildren is called from the regular diff so if it happens to throw we'll and up in the same catch as the one mentioned above.

@tyler-graham-ck

Copy link
Copy Markdown

ah ok, so then diffed is just a callback to be executed when the diffing is done?

@robertknight robertknight left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, except that exceptions in the effect invocations in the _render and _commit options hooks defined in hooks/src/index.js are not caught. If you wanted to handle the latter case in a separate PR, since it refers to the useLayoutEffect hook, I'd be fine with that.

Comment thread hooks/src/index.js
@JoviDeCroock

Copy link
Copy Markdown
Member Author

One last scenario is throwing in useLayoutEffect this can error out because we are reusing the commitQueue with objects (x._value()) instead of x(). So if a useLayoutEffectt throws that is not removed from the commitQueue and will just run the commitQueue afterwards (since this is part of the options hook)

This PR: #2203 can solve that more easily

Comment thread src/diff/index.js Outdated

@cristianbote cristianbote left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 great work Jovi!

Comment thread src/diff/index.js

@marvinhagemeister marvinhagemeister left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome work! 👍 💯

@marvinhagemeister

Copy link
Copy Markdown
Member

@robertknight with the new changes in this PR errors in _commit will be caught. Just checked with @JoviDeCroock regarding _render and imo it's "edge-casy" enough that we can move that to another PR. We only flush effects there on synchronous rendering. Example from our test suite:

it('works with closure effect callbacks capturing props', () => {
  const values = [];

  function Comp(props) {
    useEffect(() => values.push(props.value));
    return null;
  }

  render(<Comp value={1} />, scratch);
  render(<Comp value={2} />, scratch);
  return scheduleEffectAssert(() => expect(values).to.deep.equal([1, 2]));
);

@JoviDeCroock JoviDeCroock merged commit 3d457f8 into master Jan 23, 2020
@JoviDeCroock JoviDeCroock deleted the fix/effect-error branch January 23, 2020 18:38
porfirioribeiro pushed a commit to porfirioribeiro/preact that referenced this pull request Feb 3, 2020
* bailout when hook throws an error

* solve more scenario's

* solve issue with double commit

* clean solution for effect-error bailing

* better solution where everything is handled in options._commit

* add accidentely removed whitespace

* add ._render test
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

Successfully merging this pull request may close these issues.

throwing in useEffect causes subsequent effects to queue and never fire

7 participants