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

Add React lifecycles getDerivedStateFromProps, getSnapshotBeforeUpdate #6511

Closed
wants to merge 5 commits into from

Conversation

motiz88
Copy link
Contributor

@motiz88 motiz88 commented Jun 23, 2018

Closes #6101, closes #6104.

Broadly speaking, there are three possible approaches for handling getSnapshotBeforeUpdate and componentDidUpdate:

  1. Type the snapshot as any and assume the user knows what they're doing (this is what I did here).
  2. Type the snapshot as mixed and force the user to cast / "promise" they know what they're doing.
  3. Add another type parameter Snapshot to React.Component, see if Flow can infer it from usage, etc.

I thought (3) was overkill for a rarely-used React feature and (2) would mostly add unhelpful noise, hence I stuck with (1). Happy to take guidance from a reviewer if you think another option is preferable though.

@motiz88
Copy link
Contributor Author

motiz88 commented Jun 23, 2018

This will have merge conflicts with #6510 which I'd be happy to resolve once either PR is merged.

@samwgoldman samwgoldman self-requested a review June 27, 2018 18:10
@mrkev
Copy link
Contributor

mrkev commented Jul 3, 2018

Can you link to documentation or code backing this change, to ensure this is the correct definition?

@motiz88
Copy link
Contributor Author

motiz88 commented Jul 17, 2018

getDerivedStateFromProps: docs, call site

getSnapshotBeforeUpdate: docs, call site

  1. I've just noticed that React emits a warning on gDSFP() === undefined, so we should probably narrow the return type to $Shape<State> | null.
  2. gSBU() === undefined also gives a warning but our return type is any per the reasoning above - do we have an idiomatic & working way of expressing "not undefined, but otherwise any"? If not, this might be a justification for typing it as some derivative of mixed.

@mrkev
Copy link
Contributor

mrkev commented Jul 17, 2018

  1. I agree
  2. Hmmm unfortunately $NonMaybeType<mixed> doesn't seem to work (I've opened an issue here $NonMaybeType<mixed> still takes null and undefined #6606). If it worked, we could use $NonMaybeType<mixed> | null, but for the time being I think mixed should do.

any kinda just short-circuits the typesystem-- mixed is generally preferred 👍

@motiz88
Copy link
Contributor Author

motiz88 commented Jul 17, 2018

  1. So apparently $Shape<T> accepts null and undefined, and $NonMaybeType<$Shape<T>> doesn't help. Happy to still make the change to getDerivedStateFromProps but this will not actually typecheck differently, nor show up in the tests. 😭
  2. @mrkev just to confirm that this is what we want, because subjectively I have my concerns: Typing the snapshot as mixed will force users to type it (not very "gradual typing" IMHO), and won't let them do it in what I think is an intuitive way:
    componentDidUpdate(prevProps, prevState, snapshot: number) { // Error: number is incompatible with mixed
      let x: number = snapshot;
    }
    I guess my point is that the snapshot behaves almost like a local variable shared between the two methods - what you put in there is what you get back (except undefined which is disallowed), even though the indirection erases the type information. Which is why, to me, typing it as mixed feels like putting up a barrier for little added value. (I would personally love it if Flow could just infer the snapshot type and enforce consistency between getSnapshotBeforeUpdate and componentDidUpdate somehow... I'm allowed to dream, right?)

@motiz88
Copy link
Contributor Author

motiz88 commented Jul 17, 2018

I can get getDerivedStateFromProps to behave if I use ($Shape<State> & Object) | null as the return type though. Would want to include a TODO comment to change it to $NonMaybeType<$Shape<State>> | null as soon as the issue's fixed.

@mrkev
Copy link
Contributor

mrkev commented Jul 18, 2018

@motiz88 I think $Shape<State> & Object works because Object works, no? Object is a super type of all objects, which should include anything returned by $Shape<T>. Or does using $Shape<State> & Object only allow the keys on State?

@motiz88
Copy link
Contributor Author

motiz88 commented Aug 6, 2018

@mrkev

$Shape<State> & Object represents the intersection of the following sets of values:

  1. All non-null objects
  2. null | void | /* all objects with the shape of State */

= objects with the shape of State.

Your comment would have been correct if I was referring to $Shape<State> | Object, which reduces to ?Object - not what we want here (we want a non-maybe $Shape<State>)

A couple of remaining issues due to facebook#6606:
- gDSFP's return type is correct, but in need of a cleanup once
$NonMaybeType<$Shape<State>> works.
- gSBU's return type still allows undefined, which should be rejected.

I have made these explicit in the code by using $FIXME-prefixed aliases.
@motiz88
Copy link
Contributor Author

motiz88 commented Aug 12, 2018

Back working on this after a busy few weeks (also helped by the fact that CI builds are working again).

8a7bb7d brings us to what I think is the best of all possible worlds right now:

  1. componentDidUpdate still takes snapshot: any, which I subjectively prefer and nobody has definitively rejected following Add React lifecycles getDerivedStateFromProps, getSnapshotBeforeUpdate #6511 (comment).
  2. getDerivedStateFromProps returns either null or $Shape<State> excluding undefined. This is the correct behaviour; It's just typed as the temporary $FIXME$NonMaybeObject<$Shape<State>> | null since $NonMaybeType<$Shape<State>> | null doesn't work ($NonMaybeType<mixed> still takes null and undefined #6606).
  3. getSnapshotBeforeUpdate returns mixed, which is not ideal because undefined should be disallowed. It's typed as the temporary $FIXME$NonMaybeMixed to draw attention to this fact (and also to "magically" fix things once $NonMaybeType<mixed> still takes null and undefined #6606 is fixed).

@nmote nmote added the Library definitions Issues or pull requests about core library definitions label Jan 3, 2019
@nmote nmote added the react label Feb 6, 2019
@goodmind goodmind added the Stalled Issues and PRs that are stalled. label Jul 27, 2019
@gkz
Copy link
Member

gkz commented Aug 18, 2024

We are not updating class component typing at this point.

@gkz gkz closed this Aug 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed Library definitions Issues or pull requests about core library definitions react Stalled Issues and PRs that are stalled.
Projects
None yet
6 participants