Hi,
It seems that all component functions are "hidden" when exported through the withStyles method.
Given a component App, using component MainDrawer that have a function toggleDrawer. When setting ref attribute on the use of MainDrawer (<MainDrawer ref={(drw) => { this.mainDrawer = drw; }} />) inside the render method in App, I should be able to call this.mainDrawer.toggleDrawer() inside component App.
When dumping this in component App I see the mainDrawer component that was added. But it doesn't contain the toggleDrawer function for some reason. If i remove the withStyles wrapper from component MainDrawer, then the toggleDrawer function appears in this.mainDrawer and can be executed.
The error I get in console is:
Uncaught TypeError: this.mainDrawer.toggleDrawer is not a function
at App.doToggle (App.js:27)
at Object.toggle (App.js:35)
at onClick (AppBarHeader.js:31)
at HTMLUnknownElement.callCallback (react-dom.development.js:542)
at Object.invokeGuardedCallbackDev (react-dom.development.js:581)
at Object.invokeGuardedCallback (react-dom.development.js:438)
at Object.invokeGuardedCallbackAndCatchFirstError (react-dom.development.js:452)
at executeDispatch (react-dom.development.js:836)
at executeDispatchesInOrder (react-dom.development.js:858)
at executeDispatchesAndRelease (react-dom.development.js:956)
at executeDispatchesAndReleaseTopLevel (react-dom.development.js:967)
at Array.forEach (<anonymous>)
at forEachAccumulated (react-dom.development.js:935)
at processEventQueue (react-dom.development.js:1112)
at runEventQueueInBatch (react-dom.development.js:3607)
at handleTopLevel (react-dom.development.js:3616)
at handleTopLevelImpl (react-dom.development.js:3347)
at batchedUpdates (react-dom.development.js:11082)
at batchedUpdates (react-dom.development.js:2330)
at dispatchEvent (react-dom.development.js:3421)
This leads me to expect that something is going on in withStyles, that leads this function to be hidden? Or maybe I have misunderstood it all.
https://github.com/lazee/material-ui-issue-withstyles
| Tech | Version |
|--------------|---------|
| Material-UI | latest next |
| React | 16.2.0 |
| browser | Chrome 65 |
| Node | 9.9.0 |
this.mainDrawer.toggleDrawer()
@lazee Calling imperative methods for controlling elements is a discouraged pattern in React. I would encourage you to use an open like property.
It doesn't contain the toggleDrawer function for some reason.
It's because the withStyles() higher order component is exposing a different component. You have to use the documented innerRef property.
Let's see if we can use forwardRef in the future to improve the story.
@oliviertassinari Thank you so much for taking the time to answer something that was already documented. I actually looked for it on the site, but must have done a terrible job. My bad.
I did realize that I was using an anti-pattern, but couldn't figure out why it didn't work. With other wrapper from other frameworks I haven't had the same issues. But what you say about "exposing a different component" makes sense. I will rewrite and use property instead.
forwardRef seems like a perfect match for theming. Also looking forward to see what can be done wi th that in the future.
AND: Thank you for Material UI. Love it!
Let's wait and see how these libraries solve the problem:
innerRef doesn't solve the problem of forwarding ref through multiple HOCs, but forwardRef does.
Also it would be possible to have both of them available to maintain backward compatibility (I guess).
@alimo You are right, having following the threads of https://github.com/mui-org/material-ui/issues/10825#issuecomment-383318055. It seems that bringing forwardRef is not trivial.
When you start using forwardRef in a component library, you should treat it as a breaking change and release a new major version of your library.
Most helpful comment
Let's wait and see how these libraries solve the problem: