-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
feat(forwardRef): add forwardRefFactory #2844
Conversation
src/lib/forwardRefFactory.js
Outdated
<Ref innerRef={ref}> | ||
<Component {...props} /> | ||
</Ref> | ||
) |
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 factory allows to use stateless components too 😺
if (prop === forwardRefSymbol) { | ||
acc.ref = props[forwardRefSymbol] | ||
return acc | ||
} |
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 hack allows to don't map ref
in the every component
@levithomason this is an initial pass, no tests, just PoC. Will be interesting to hear your thoughts. |
Could add |
src/lib/forwardRefFactory.js
Outdated
export const forwardRefFactory = (Component) => { | ||
const forwarder = forwardRef(forwardFunctionFactory(Component)) | ||
|
||
hoistStatics(forwarder, Component, { $$typeof: true, render: true }) |
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.
Why do we hoist { $$typeof: true, render: true }
here? Also, the values are conflicting with the docblock on this function.
src/lib/componentUtils.js
Outdated
* @return {Object} | ||
*/ | ||
export const isClassComponent = Component => | ||
typeof Component === 'function' && Component.prototype && !!Component.prototype.isReactComponent |
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.
Perhaps we also add:
export const isStatelessComponent = Component =>
typeof Component === 'function' && Component.prototype && !Component.prototype.render
export const supportsRef = Component =>
typeof Component === 'string' || isClassComponent(Component)
It may help clarify the factory function, see below.
src/lib/forwardRefFactory.js
Outdated
// eslint-disable-next-line react/prop-types | ||
if (_.isUndefined(props.as) || _.isString(props.as) || isClassComponent(props.as)) { | ||
return <Component {...{ [forwardRefSymbol]: ref, ...props }} /> | ||
} |
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.
What do you think of explicitly handling the ref for supported use cases and returning the Component in all other cases?:
import { isStatelessComponent, supportsRef } from './componentUtils.js'
export const forwardFunctionFactory = Component => (props, ref) => {
/* eslint-disable react/prop-types */
if (isStatelessComponent(props.as)) {
return (
<Ref innerRef={ref}>
<Component {...props} />
</Ref>
)
}
if (supportsRef(props.as)) {
return <Component {...{ [forwardRefSymbol]: ref, ...props }} />
}
return Component
}
This implementation is far better, thanks! Also, this pattern should definitely be implemented in the v2 fork. I'm about to post a set of specification proposals for the |
Signed-off-by: Oleksandr Fediashov <[email protected]>
Signed-off-by: Oleksandr Fediashov <[email protected]>
9823412
to
4b94607
Compare
We decided to stop our work there, microsoft/fluent-ui-react#587 (comment). There is a RFC reactjs/rfcs#97 that possibly will simplify all. |
Replaces #2306.
React 16.3 gives the wonderful
forwardRef
API, this PR implements theforwardRefFactory
that allows to use it.Some ideas are taken from klimashkin/react-forwardref-utils.