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

Rewrite useImperativeHandle to use useLayoutEffect (-35 B) #2003

Merged
merged 12 commits into from
Oct 20, 2019

Conversation

andrewiggins
Copy link
Member

This PR brings some improvements to hooks that @JoviDeCroock and I have been playing with in other branches for a little while into master.

@JoviDeCroock I thought I'd bring these in a separate PR cuz I have a couple different branches I'd like to build on top of them. That alright?

@coveralls
Copy link

coveralls commented Oct 12, 2019

Coverage Status

Coverage increased (+0.1%) to 99.767% when pulling 6930462 on hooks-golf into 48bd8b5 on master.


if (index >= hooks._list.length) {
hooks._list.push({});
}
return hooks._list[index];
}

/**
* @param {import('./index').StateUpdater<any>} initialState
*/
export function useState(initialState) {
Copy link
Member Author

Choose a reason for hiding this comment

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

When I tested it, converting this to useReducer.bind seemed to increase the size so I left it as is for now.

Copy link
Member

@marvinhagemeister marvinhagemeister left a comment

Choose a reason for hiding this comment

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

I'm impressed with how much you and Jovi are able to golf our hooks implementation. Outstanding stuff here 👍💯

hooks/src/index.js Outdated Show resolved Hide resolved
prevRaf !== options.requestAnimationFrame) {
if (
(!component._afterPaintQueued && (component._afterPaintQueued = afterPaintEffects.push(component)) === 1)
|| prevRaf !== options.requestAnimationFrame
Copy link
Member

Choose a reason for hiding this comment

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

Hmm - I'm wondering how common the case of swapping options.requestAnimationFrame is that we'd need this. Was there a specific case where this was troublesome? Only thing I could think of was injecting a super long rAF and then wanting to cancel.

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't think its very common and personally would love to save some bytes here (-24 bytes!). It was orginally added in #1851 so perhaps @robertknight could chime and let us know his thoughts? Perhaps if we could fix the original act issue from #1851 in a different way, could we perhaps remove this check here?

Copy link
Member

Choose a reason for hiding this comment

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

I am sure that the issue captured by the tests in #1851 should stay fixed, i.e. act needs to reliably flush any renders/effects triggered during its callback regardless of whether there are renders/effects happening outside of act callbacks or not. Tests can break in very confusing ways otherwise.

The Enzyme adapter installs a debounceRendering hook to ensure that it can flush pending state updates when Enzyme asks for the current render output. It doesn't access requestAnimationFrame though, so if you can find an alternative way to keep the tests added in #1851 passing, that would be fine from my point of view.

/**
* @param {any[]} oldArgs
* @param {any[]} newArgs
*/
function argsChanged(oldArgs, newArgs) {
return !oldArgs || newArgs.some((arg, index) => arg !== oldArgs[index]);
Copy link
Member

Choose a reason for hiding this comment

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

I know it's not part of this PR, but I wonder if this is smaller after gzip?

Suggested change
return !oldArgs || newArgs.some((arg, index) => arg !== oldArgs[index]);
if (!oldArgs || oldArgs.length!==newArgs.length) return;
for (let i=newArgs.length; i--; ) if (newArgs[i]!==oldArgs[i]) return;
return true;

Copy link
Member Author

Choose a reason for hiding this comment

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

No worries. All comments welcome 😄

This function returns true if the args are different so I think the return values need to be swapped like so:

Suggested change
return !oldArgs || newArgs.some((arg, index) => arg !== oldArgs[index]);
if (!oldArgs || oldArgs.length!==newArgs.length) return true;
for (let i=newArgs.length; i--; ) if (newArgs[i]!==oldArgs[i]) return true;
return;

In my tests it adds 21 B. However, given that argsChanged is potentially run a lot in render methods, perhaps it might be worth the bytes for the perf boost? (I'm assuming a for loop is marginally faster than .some).

@andrewiggins andrewiggins changed the title Rewrite useImperativeHandle to use useLayoutEffect (-41 B) Rewrite useImperativeHandle to use useLayoutEffect (-29 B) Oct 13, 2019
...since its implementation does more than a real `safeRaf` implementation. In other words, `safeRaf` invokes the callback after a rAF (or timeout) and another timeout (line 241) so its not a pure `safeRaf`. So to avoid confustion, I renamed the function to be clearer and added a comment describing its purpose
Copy link
Member

@JoviDeCroock JoviDeCroock left a comment

Choose a reason for hiding this comment

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

LGTM 👍 I'd merge it but there's a minor conflict I won't touch that

@andrewiggins andrewiggins changed the title Rewrite useImperativeHandle to use useLayoutEffect (-29 B) Rewrite useImperativeHandle to use useLayoutEffect (-35 B) Oct 19, 2019
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.

7 participants