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

[core] forward innerRef for certain components #14536

Merged
merged 35 commits into from
Mar 1, 2019

Conversation

eps1lon
Copy link
Member

@eps1lon eps1lon commented Feb 14, 2019

It's recommended to review one commit at a time.

Two reasons I already open this:

  • I wanted to see what Draft Pull Request offers
  • I consider the individual commits itself complete. If anybody has some spare time early review would be more than welcome.

Breaking

Wraps components in forwardRef. Since every component is wrapped in withStyles this will only affect the innerRef prop. They will no longer return a ref to the instance (or error for function components) but rather the underlying DOM node where useful1.

Some components are not included (yet). Those are the ones where virtually no test was passing so I defer them to a separate PR:

The initial change broke about 25% of our unit tests. Some of them were due to own mistakes, some because forwardRef was not appropriate but overall I suspect 15% of the breakage was due to flawed tests. I think https://blog.kentcdodds.com/why-i-never-use-shallow-rendering-c08851a68bb7 is a pretty good starting point to explain why.

Implementation details

  • function components are simply wrapped in their original function. I may rename the component var names later because const Foo = React.forwardRef(function Foo() {}) is quite tricky WRT to what Foo actually references
  • class components are wrapped in a withForwardRef HOC that injects the ref from forwardRef into innerRef. Since that prop is intercepted by withStyles it does not cause any property collision.

Notes for reviewers

Looking through one function and one class component implementation is sufficient. The rest follow the same pattern. The critical parts are the test files.

1 This excludes TouchRipple. We need imperative handles here (see useImperativeHandle to trigger pulsating).

@eps1lon eps1lon added this to the v4 milestone Feb 14, 2019
@oliviertassinari
Copy link
Member

Could we run the CI?

@eps1lon
Copy link
Member Author

eps1lon commented Feb 14, 2019

Could we run the CI?

Sure. But it's far from ready yet and I didn't want to waste resources.

@oliviertassinari
Copy link
Member

oliviertassinari commented Feb 14, 2019

Sure. But it's far from ready yet and I didn't want to waste resources.

@eps1lon Thanks, I was interested in the bundle size.

My biggest issue is how we gonna educate people to correctly apply the ref when implementing custom components. 90% of the libraries of the community doesn't correctly forward the reference. I have just tested react-router. I can't get a ref on the DOM an element when using the Link. They don't seem to be interested in solving the problem: remix-run/react-router#6195. Same push back from reactjs/react-transition-group#457. When I all the changes needed, maybe the best move it to "wait and see" 🤔 but it has almost been 1 year since: #10825 (comment).

@eps1lon
Copy link
Member Author

eps1lon commented Feb 14, 2019

You can patch react-router-dom by wrapping it in another component: https://github.com/mui-org/material-ui/pull/13664/files#diff-52b99e4a854fd9a4fc16ebc3353cd14dR131

This approach should work with most libraries. As far as I know most of the libraries have some sort of innerRef prop.

Come to think of it it might be possible to check if a component allows refs to the DOM node (forwardRef or string elementType) and use ref in those cases, otherwise assume innerRef works. Will need to check how much complexity this adds.

Overall even if this adds to much complexity we can still cherry-pick changes from here. Things like aria-disabled on non-html Button or a more robust test suite is probably a good thing.

@eps1lon eps1lon force-pushed the feat/forwar-ref branch 5 times, most recently from e426edc to 786fcf5 Compare February 21, 2019 17:22
@mui-pr-bot
Copy link

mui-pr-bot commented Feb 21, 2019

@material-ui/core: parsed: +0.81% , gzip: +0.44%
@material-ui/lab: parsed: +0.70% , gzip: +0.71%

Details of bundle changes.

Comparing: 56fcebb...827b466

bundle parsed diff gzip diff prev parsed current parsed prev gzip current gzip
@material-ui/core +0.81% 🔺 +0.44% 🔺 369,244 372,227 91,572 91,973
@material-ui/core/Paper +0.37% 🔺 +0.40% 🔺 76,648 76,931 19,296 19,373
@material-ui/core/Paper.esm +0.01% 🔺 +0.03% 🔺 71,596 71,601 18,774 18,779
@material-ui/core/Popper 0.00% +0.02% 🔺 30,462 30,462 10,580 10,582
@material-ui/core/styles/createMuiTheme 0.00% 0.00% 17,286 17,286 5,717 5,717
@material-ui/core/useMediaQuery 0.00% +0.10% 🔺 2,486 2,486 1,050 1,051
@material-ui/lab +0.70% 🔺 +0.71% 🔺 183,226 184,506 50,374 50,730
@material-ui/styles +0.04% 🔺 +0.02% 🔺 57,708 57,733 16,229 16,233
@material-ui/system 0.00% 0.00% 17,062 17,062 4,485 4,485
Button +0.56% 🔺 +0.59% 🔺 99,076 99,633 26,477 26,634
Modal +0.01% 🔺 +0.03% 🔺 98,865 98,871 26,218 26,227
colorManipulator 0.00% -0.08% 3,232 3,232 1,297 1,296
docs.landing +0.07% 🔺 +0.17% 🔺 49,899 49,934 10,728 10,746
docs.main +0.19% 🔺 +0.17% 🔺 678,034 679,298 205,987 206,347
packages/material-ui/build/umd/material-ui.production.min.js +0.75% 🔺 +0.46% 🔺 320,385 322,787 84,772 85,165

Generated by 🚫 dangerJS against 827b466

@eps1lon eps1lon force-pushed the feat/forwar-ref branch 3 times, most recently from 730364e to 6491c4c Compare February 24, 2019 19:31
@eps1lon eps1lon marked this pull request as ready for review February 24, 2019 19:42
Copy link
Member

@oliviertassinari oliviertassinari left a comment

Choose a reason for hiding this comment

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

Great work! I'm rebasing on next so we can merge :)

@oliviertassinari oliviertassinari mentioned this pull request Mar 1, 2019
1 task
This was referenced Mar 1, 2019
eps1lon added a commit that referenced this pull request Mar 4, 2019
Little bit different approach this time: Refactored tests first then implementation. Definitely still biased because I knew how the implementation would look like but still increased confidence in tests for me.

I need to investigate the shallow + disableLifeCycleIssue. This is causing enzyme to call componentDidMount if we wrap it in `forwardRef`.

Continues #14536
@eps1lon eps1lon mentioned this pull request Mar 4, 2019
@eps1lon eps1lon deleted the feat/forwar-ref branch March 4, 2019 16:35
@eps1lon eps1lon mentioned this pull request Mar 4, 2019
eps1lon added a commit that referenced this pull request Mar 5, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants