-
-
Save jamesreggio/142215754ad06f375bd87657c6227ed8 to your computer and use it in GitHub Desktop.
// EmailInput wraps an HTML `input` and adds some app-specific styling. | |
const EmailInput = React.forwardRef((props, ref) => ( | |
<input ref={ref} {...props} type="email" className="AppEmailInput" /> | |
)); | |
class App extends Component { | |
emailRef = React.createRef(); | |
render() { | |
return ( | |
<div> | |
<EmailInput ref={this.emailRef} /> | |
<button onClick={() => this.onClickButton()}> | |
Click me to focus email | |
</button> | |
</div> | |
); | |
} | |
// `this.emailRef.current` points to the `input` component inside of EmailInput, | |
// because EmailInput is forwarding its ref via the `React.forwardRef` callback. | |
onClickButton() { | |
this.emailRef.current.focus(); | |
} | |
} |
@dheeraj-br ref
won't appear in child component's props when the component is not wrapped in React.forwardRef
. It's a special case like key
, not a normal property.
@zmeyc but if we will pass it as refSomething
, it will be in props) So, what the difference?)
@artem-malko As I understand, in <Wrapper ref=...>
, ref
refers to wrapper component itself. I.e. React processes it and removes from props. If it's desirable to reference wrapped (child) component instead, it's possible to link wrapper's ref to child using forwardRef.
You're right that it's also possible to expose child's ref via a custom property, but this can be counter-intuitive for lib's users as name of the property can't be easily discovered. For example, if there's EnhancedInput
wrapping <input>
, users would probably expect that <EnhancedInput ref=...
would reference actual <input>
from where they can get the value etc and not the wrapper.
@zmeyc ok, thx)
I feel this discussion also explains better - forwardRef
function vs a custom ref
https://stackoverflow.com/questions/58578570/value-of-using-react-forwardref-vs-custom-ref-prop
We use both in our project and while the former offers a way to pass a reference to the inner elements (to the root element that actually appears in the HTML dom), the latter can provide a way to pass ones that you already have might have declared in the component that is calling another.
Example: Check out use-resize-observer
package: https://github.com/ZeeCoder/use-resize-observer
thanks work fine for my case !
here cool example for types and control a powerful componement
export const Box = React.forwardRef(
/**
* @typedef {Object} FlexOption
* @property {React.CSSProperties['display']} [FlexOption.display]
* @property {React.CSSProperties['flexDirection']} [dir]
* @property {React.CSSProperties['flexGrow']} [grow]
* @property {React.CSSProperties['flexFlow']} [flow]
* @typedef {Object} props
* @property {boolean | FlexOption} [Flex] -
* @property {boolean | 'reverse' } [Column] -
* @property {boolean | number } [Grow] -
* @property { React.CSSProperties['position'] } [Position] -
* @property {bgcolor} [ColorBg] - colors
* @property {boolean|number} [Fit] - number % w,h
* @property {boolean|React.CSSProperties['overflowX']} [OverflowX] -
* @property {boolean|React.CSSProperties['overflowY']} [OverflowY] -
* @property {number|{x:number,y:number}|[number,number,number,number]} [P] - padding: [ left, top, right, bottom ]
* @property {number|'auto'|{x:number,y:number}|[number,number,number,number]} [M] - margin: [ left, top, right, bottom ]
* @typedef {props & React.HTMLAttributes<HTMLDivElement> } Child
* @param {Child} props Component props
*/
(
{ Flex, Column, Grow, ColorBg, Fit, Position, P, M, OverflowX, OverflowY, children, style = {}, ...rest },
ref,
) => {
if (Flex || Column) {
style.display = style.display || 'flex';
}
if (Column) {
style.flexDirection = _.isString(Column) ? 'column-reverse' : 'column';
}
if (Grow) {
style.flexGrow = +Grow;
}
if (Position) {
style.position = Position;
}
if (ColorBg) {
style.backgroundColor = ColorBg;
}
if (OverflowX || OverflowY) {
style.overflowX = _.isBoolean(OverflowX) ? 'scroll' : OverflowX;
style.overflowY = _.isBoolean(OverflowY) ? 'scroll' : OverflowY;
}
if (Fit) {
style.minWidth = '0px';
style.minHeight = '0px';
style.width = '100%';
style.height = '100%';
}
if (P) {
style.padding = _.isNumber(P)
? `${P}px ${P}px ${P}px ${P}px`
: _.isArray(P)
? `${P[0]}px ${P[1]}px ${P[2]}px ${P[3]}px`
: `${P.x}px ${P.x}px ${P.y}px ${P.y}px`;
}
if (M) {
style.margin = _.isNumber(M)
? `${M}px ${M}px ${M}px ${M}px`
: _.isArray(M)
? `${M[0]}px ${M[1]}px ${M[2]}px ${M[3]}px`
: `${M.x}px ${M.x}px ${M.y}px ${M.y}px`;
}
return (
<div ref={ref} {...rest} style={style}>
{children}
</div>
);
},
);
Yes, i have the same question. can anyone mention the usecase of forwardRef that cant be achieved by sending refs as props? there must be a reason for introducing forwardRef
Have a look at this code https://codesandbox.io/s/snowy-feather-yrsjwn?file=/src/App.js
It is a simple example of both, passing ref as props as well as using forwardRef
Yes, i have the same question. can anyone mention the usecase of forwardRef that cant be achieved by sending refs as props? there must be a reason for introducing forwardRef