Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to add ref to the props.children elements?

I have a Form and Input components, which are rendered as below.

<Form>
   <Field />
   <Field />
   <Field />
</Form>

Form component will act as wrapper component here and Field component ref are not being set here. I want iterate through props.children in Form Component and want to assign a ref attribute to each children. Is there any possibility to achieve this?

like image 776
itzzmeakhi Avatar asked Aug 30 '20 06:08

itzzmeakhi


People also ask

How do you use REF in child components?

In child component, we create Refs by using React. createRef() and then attached to React elements via the ref attribute. // EXPLANATION: a reference to the node becomes accessible at the current attribute of the ref. In the parent component, we can get a reference to the Input component and call its focus() method.

Can you pass a ref as a prop React?

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.

How do you get the child element in ref in React?

then using Refs we can access the child's state. Creating Refs Refs are created using React. createRef() and attached to React elements via the ref attribute. Accessing Refs When we assign a ref to an element or child component in the render, then we can access the element using the current attribute of the ref.

Can we change props in child component?

Solution : As I had mentioned earlier — there are no direct ways to mutate a prop directly in child components. However when we pass the props from parent to child, we can also pass the function(with the logic) which changes the props.


2 Answers

You need Form to inject your refs with React.Children and React.cloneElement APIs:

const FunctionComponentForward = React.forwardRef((props, ref) => (
  <div ref={ref}>Function Component Forward</div>
));

const Form = ({ children }) => {
  const childrenRef = useRef([]);

  useEffect(() => {
    console.log("Form Children", childrenRef.current);
  }, []);

  return (
    <>
      {React.Children.map(children, (child, index) =>
        React.cloneElement(child, {
          ref: (ref) => (childrenRef.current[index] = ref)
        })
      )}
    </>
  );
};

const App = () => {
  return (
    <Form>
      <div>Hello</div>
      <FunctionComponentForward />
    </Form>
  );
};

Edit Vanilla-React-Template (forked)

like image 181
Dennis Vash Avatar answered Nov 15 '22 04:11

Dennis Vash


You can map children create new instance of component based on it using one of two ways showed in React Docs.

  • With React.Children.map and React.cloneElement (this way, key and ref from original element are preserved)

  • Or only with React.Children.map (Only ref from original component is preserved)

function useRefs() {
  const refs = useRef({});

  const register = useCallback((refName) => ref => {
    refs.current[refName] = ref;
  }, []);

  return [refs, register];
}

function WithoutCloneComponent({children, ...props}) {

 const [refs, register] = useRefs(); 

 return (
    <Parent>
     {React.Children.map((Child, index) => (
       <Child.type 
         {...Child.props}
         ref={register(`${field-${index}}`)}
         />
    )}
    </Parent>
 )
}

function WithCloneComponent({children, ...props}) {

 const [refs, register] = useRefs(); 

 return (
    <Parent>
     {
       React.Children.map((child, index) => React.cloneElement(
         child, 
         { ...child.props, ref: register(`field-${index}`) }
       )
    }
    </Parent>
 )
}
like image 28
Bruno Cardoso Avatar answered Nov 15 '22 04:11

Bruno Cardoso