-
Notifications
You must be signed in to change notification settings - Fork 203
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
Bump preact from 10.5.13 to 10.5.15 #3845
Conversation
c8509b1
to
b524ce9
Compare
Codecov Report
@@ Coverage Diff @@
## master #3845 +/- ##
=======================================
Coverage 98.98% 98.98%
=======================================
Files 211 211
Lines 7904 7904
Branches 1870 1871 +1
=======================================
Hits 7824 7824
Misses 80 80
Continue to review full report at Codecov.
|
I have added a commit which shows a possible solution to the increased An alternative approach would be to patch the Preact typings locally to revert |
Bumps [preact](https://github.com/preactjs/preact) from 10.5.13 to 10.5.15. - [Release notes](https://github.com/preactjs/preact/releases) - [Commits](preactjs/preact@10.5.13...10.5.15) --- updated-dependencies: - dependency-name: preact dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
2382576
to
a9d6dd5
Compare
src/sidebar/components/Excerpt.js
Outdated
}, [collapsedHeight, onCollapsibleChanged, overflowThreshold]); | ||
}, [ | ||
collapsedHeight, | ||
contentElement, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately ESLint plugin for React doesn't know that useElementRef
returns an immutable value that therefore doesn't need to be listed in the dependencies array. Would be worth checking if there is a config option to avoid this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately it looks like there isn't a config option to declare that a custom hook returns a stable result (ie. one that does not change across renders). See facebook/react#22539.
src/sidebar/components/MenuItem.js
Outdated
@@ -141,6 +140,7 @@ export default function MenuItem({ | |||
// The menu item is a link | |||
menuItem = ( | |||
<a | |||
// @ts-ignore |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a hack to deal with the fact that this ref may be assigned to either an HTMLAnchorElement
or an HTMLDivElement
and the useElementRef
API only supports one type. I'm sure there will be a better way to handle this.
@@ -144,5 +144,5 @@ export function useStoreProxy() { | |||
return cleanup; | |||
}, [cache, store]); | |||
|
|||
return proxy.current; | |||
return /** @type {SidebarStore} */ (proxy.current); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is non-null cast here, which we know is safe in this context.
src/shared/hooks.js
Outdated
* @return {{ current: InstanceType<T> }} | ||
*/ | ||
// eslint-disable-next-line no-unused-vars | ||
export function useElementRef(type) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The type
argument is currently unused and is purely a hint to TS. We could perhaps use it for an instanceof
check in the current
field setter in future, maybe only in development builds.
setGroupId(groupId); | ||
} | ||
); | ||
const newEmitter = eventBus.createEmitter(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These changes fix two complaints about emitter.current
being possibly null. In the subscribe
call we know that's not the case. In the cleanup callback that useEffect
returns however there is the possibility that emitter.current
gets re-assigned before the callback is run. The change here avoids that hazard.
I believe it is a good thing that preact has made the refs nullable. I think that would prevent the pitfall of believing a ref has been assigned when it didn't because it was conditionally created or rendered. Instead of the solution presented in this PR, I would suggest to evaluate all our current usage of I would suggest this more concise version to define the types:
If we know for sure that certain ref will be assigned, I suggest this other type (which is not much longer):
|
5797efb
to
2bfa29e
Compare
Hi @esanzgar - I agree with your suggestion. Casting the result of I have pushed a replacement second commit on this branch which changes all instances of: const someRef = useRef(/** @type {T|null} */ (null)); To one of: const nonNullRef = /** @type {{ current: T }} */ (useRef());
const nullRef = /** @type {{ current: T|null }} */ (useRef(null)); Given how common this is in the code, we could maybe shorten it down in future by introducing a global |
@@ -60,6 +60,9 @@ function AnnotationShareControl({ | |||
const closePanel = () => setOpen(false); | |||
|
|||
// Interactions outside of the component when it is open should close it | |||
// | |||
// @ts-expect-error - `useElementShouldClose` requires a non-nullable ref, | |||
// but `shareRef` is nullable. | |||
useElementShouldClose(shareRef, isOpen, closePanel); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a bug here, but since it is not a new one, I just suppressed the error for the moment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shareRef
is a non null ref, why not to use the pattern you suggested: const shareRef = /** @type {{ current: HTMLDivElement }} */ (useRef());
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shareRef
is a nullable ref! - There is a return null
statement in the component mid-way down with an issue link above it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, you are right. I was looking for return null
but closer to the return of the component and I didn't find it...
Then, yes I agree that adding the ts-expect-error
is the best option for now.
2bfa29e
to
89201db
Compare
Adapt to changes in useRef types in Preact v10.5.15 by using the pattern described in hypothesis/client#3845 (comment) to cast the result of `useRef`.
I applied the pattern mention in #3845 (comment) in the LMS app: hypothesis/lms#3234. |
Adapt to changes in useRef types in Preact v10.5.15 by using the pattern described in hypothesis/client#3845 (comment) to cast the result of `useRef`.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe that the input ref in the MarkdownEditor
is conditionally rendered.
You have suggested two patterns for the useRef
's type:
const nonNullRef = /** @type {{ current: T }} */ (useRef());
const nullRef = /** @type {{ current: T|null }} */ (useRef(null));
However, the pattern: const nullRef = useRef(/** @type {T|null} */ (null));
is still present. Do you have plans to change that for the new nullRef style you suggest above?
@@ -60,6 +60,9 @@ function AnnotationShareControl({ | |||
const closePanel = () => setOpen(false); | |||
|
|||
// Interactions outside of the component when it is open should close it | |||
// | |||
// @ts-expect-error - `useElementShouldClose` requires a non-nullable ref, | |||
// but `shareRef` is nullable. | |||
useElementShouldClose(shareRef, isOpen, closePanel); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shareRef
is a non null ref, why not to use the pattern you suggested: const shareRef = /** @type {{ current: HTMLDivElement }} */ (useRef());
@@ -398,7 +398,7 @@ export default function MarkdownEditor({ | |||
const [preview, setPreview] = useState(false); | |||
|
|||
// The input element where the user inputs their comment. | |||
const input = useRef(/** @type {HTMLTextAreaElement|null} */ (null)); | |||
const input = /** @type {{ current: HTMLTextAreaElement }} */ (useRef()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this ref could be null (it is conditionally rendered).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh indeed, you're right. I'll correct this.
const emitter = useRef( | ||
/** @type {ReturnType<eventBus['createEmitter']>|null} */ (null) | ||
); | ||
const emitterRef = /** @type {{ current: Emitter|null }} */ (useRef(null)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe trimming start and end whitespaces?
const emitterRef = /** @type {{ current: Emitter|null }} */ (useRef(null)); | |
const emitterRef = /** @type {{current: Emitter|null}} */ (useRef(null)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have a hugely strong aesthetic preference here, but I used whitespace because that's how Prettier formats a type in TS (ie. if you write type Ref = {current: HTMLElement}
in a TS file and format it) and also how the majority of our current inline object types are formatted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, sure.
`useRef(null as T|null)` now returns a `{ current: T|null }` instead of `{ current: T }` as it did before. ie. it no longer drops the the null. This makes sense but conflicted with a pattern we used in many places to create a non-null ref: `useRef(/** @type {T|null} */ (null))`. Resolve this by changing all non-nullable refs, for elements which are set after the initial render, to cast the `useRef` result instead of the init value. ``` const nonNullRef = /** @type {{ current: T }} */ (useRef()); ```
11fd7d1
to
2dd33bf
Compare
Hmm. Looking at this again today made me change my mind. It would have made the two styles of element ref consistent, but it would then be inconsistent with other non-element refs. I've changed it back to be much more like your original suggestion, with the only change being to use an explicit |
@@ -60,6 +60,9 @@ function AnnotationShareControl({ | |||
const closePanel = () => setOpen(false); | |||
|
|||
// Interactions outside of the component when it is open should close it | |||
// | |||
// @ts-expect-error - `useElementShouldClose` requires a non-nullable ref, | |||
// but `shareRef` is nullable. | |||
useElementShouldClose(shareRef, isOpen, closePanel); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, you are right. I was looking for return null
but closer to the return of the component and I didn't find it...
Then, yes I agree that adding the ts-expect-error
is the best option for now.
Bumps preact from 10.5.13 to 10.5.15.
Release notes
Sourced from preact's releases.
... (truncated)
Commits
bd52611
10.5.15 (#3282)9ae9f03
Avoid leaking internal vnodes (#3106)51bfe15
UseRef
to acceptRefCallback
(#3214)d78746c
[compat] Skip rendering <noscript> contents on the client (#3238)6d0f682
Update babel.config.js (#3265)4aaecc1
Merge pull request #3271 from RRDAWLX/master2d7ba34
polish: delete redundant previousComponent in hooks98f130e
Merge pull request #3260 from preactjs/bugfix-suspended-missing-children2624d51
Merge branch 'master' into bugfix-suspended-missing-childrenfe3d375
Merge pull request #2859 from nmondon/fix-dominant-baseline-attrDependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting
@dependabot rebase
.Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
@dependabot rebase
will rebase this PR@dependabot recreate
will recreate this PR, overwriting any edits that have been made to it@dependabot merge
will merge this PR after your CI passes on it@dependabot squash and merge
will squash and merge this PR after your CI passes on it@dependabot cancel merge
will cancel a previously requested merge and block automerging@dependabot reopen
will reopen this PR if it is closed@dependabot close
will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually@dependabot ignore this major version
will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this minor version
will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this dependency
will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)