Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

pass forwardRef via cloneElement reactjs

const ref = useRef()  

 React.Children.map(this.props.children, (element) => {
   React.cloneElement(element, { 
     innerRef: node => ref,
   })
 })

here element is a component

like the following

const newComponent = forwardRef(({children, ...otherprops}, ref){
    return (
     <div {...otherprops} ref={otherprops.innerRef}>
       {children}
     </div>
    )        
})

getting ref is null in forwardRef...

Reproducible example :- https://codesandbox.io/s/forward-ref-cloneelement-1msjp

like image 525
Dhanush Bala Avatar asked Nov 11 '19 14:11

Dhanush Bala


1 Answers

Try changing innerRef to ref, you adding innerRef property and expecting it to be valid at ref:

import React, { useRef } from 'react';

function RefForm(props) {
  const setRefs = useRef(new Map()).current;
  const { children } = props;
  return (
    <div>
      {React.Children.map(children, child => {
        return React.cloneElement(child, {
//         v not innerRef
          ref: node => {
            console.log('imHere');
            return !node
              ? setRefs.delete(child.key)
              : setRefs.set(child.key, node);
          }
        });
      })}
    </div>
  );
}

export default RefForm;

Then you can access the ref as you like:

const Email = React.forwardRef((props, ref) => {
  console.log('email--', ref);
  ref(); // logs "imHere"
  return (
    <div style={{ marginTop: '30px' }}>
      <label>this is email</label>
      <input name="email" ref={props.innerRef} />
    </div>
  );
});

Edit forward-ref-cloneelement

Edit:

For class components need to use another key then ref.

There is one caveat to the above example: refs will not get passed through. That’s because ref is not a prop. Like key, it’s handled differently by React. If you add a ref to a HOC, the ref will refer to the outermost container component, not the wrapped component.

// class component
class Name extends Component {
  render() {
    console.log('name--', this.props.innerRef);

    return (
      <div style={{ marginTop: '30px' }}>
        <label>this is name</label>
        <input name="name" ref={this.props.innerRef} />
      </div>
    );
  }
}

// functional component
const Email = props => {
  console.log('email--', props.innerRef);
  return (
    <div style={{ marginTop: '30px' }}>
      <label>this is email</label>
      <input name="email" ref={props.innerRef} />
    </div>
  );
};

// cloneElement
function RefForm(props) {
  const setRefs = useRef(new Map()).current;
  const { children } = props;
  return (
    <div>
      {React.Children.map(children, child => {
        return React.cloneElement(child, {
          innerRef: node => {
            return !node
              ? setRefs.delete(child.key)
              : setRefs.set(child.key, node);
          }
        });
      })}
    </div>
  );
}

Edit Q-58803654-forwardRefInClass


Further, read:

  • Why, exactly, do we need React.forwardRef?
like image 169
Dennis Vash Avatar answered Oct 24 '22 02:10

Dennis Vash