Home > Software design >  Listening to events fired from Children component in Parent Component in React
Listening to events fired from Children component in Parent Component in React

Time:12-25

How do i listen to children events in parent component?

Look at my code what i am trying to achieve.

Page Component

interface PageProps {}
const Page: FC<PageProps> = ({}) => {
//I don't want to bind handlers here and bind it to Parent.
return (
    <div>
        <Parent>
            <>
                <Child />
                <Child />
                <Child />
                <Child />
            </>
        </Parent>
    </div>
)}
export default Page;

Child Component

import { FC } from 'react';
import AnotherChild from '../components';
interface IProps {
    handleChange?: (value: string) => void;
}
const Child: FC<IProps> = ({ handleChange }) => {
    //Methods
    const onChange = (value: string) => {
        handleChange ? handleChange(value) : null;
    }   
    return (
    <div>
        <AnotherChild onChange={onChange} />
    </div>
    )
}
export default Child;

Parent Component

import React, { FC, Children, cloneElement, isValidElement } from 'react';
interface IProps {
    children: React.ReactNode
}
const Parent: FC<IProps> = ({ children }) => {
    //Methods
    const handleChange = (value: string) => {
        console.log("VALUE: ", value)
    }
    const arrChildren = Children.toArray(children);
    return (
        <div>
            {
                arrChildren.map((child, index) => {
                    return (
                        React.cloneElement(child, { handleChange: handleChange })
                    )
                })
            }
        </div>
    )
}
export default Parent;

So, I have children components which is emitting handleChange event, I want to listen those events in my <Parent /> component which is wrapped around.

Look at my <Page /> Component that is how those components will be called.

I have tried something you can look at my code but i am not getting those events.

Please help me to figure it out what i was doing wrong here.

Thank you

CodePudding user response:

well, you did have the correct idea for listening to child events. the problem is that you wrapped the child components inside a React.Fragment. I think you did that because of the type of child props. the witch says children: React.ReactNode. change that to children: React.ReactNode | React.ReactNode[] and then remove the fragment.

you should have something like this.

interface IProps {
    handleChange?: (value: string) => void;
}
const Child: FC<IProps> = ({ handleChange }) => {
    const onChange = (value: string) => {
        handleChange ? handleChange(value) : null;
    }   
    return (
    <div>
        <AnotherChild onChange={onChange} />
    </div>
    )
}

interface IProps {
    children: React.ReactNode | React.ReactNode[]
}
const Parent: FC<IProps> = ({ children }) => {
    const handleChange = (value: string) => {
        console.log("VALUE: ", value)
    }
    const arrChildren = Array.isArray(children) ? children : [children];
    return (
        <div>
            {
                arrChildren.map((child, index) => {
                    return (
                        React.cloneElement(child, { handleChange: handleChange })
                    )
                })
            }
        </div>
    )
}

const Page: FC<PageProps> = ({}) => {
return (
    <div>
        <Parent>
            <Child />
            <Child />
            <Child />
            <Child />
        </Parent>
    </div>
)}

CodePudding user response:

Assuming that the goal is to add a handleChange to props of the Child from the wrapper Parent, according to React document, perhaps try the following way of using cloneElement in this use case:

Simplified live demo on: stackblitz

Page Component:

interface PageProps {}
const Page: FC<PageProps> = ({}) => {
  return (
    <div>
      <Parent>
        {[1, 2, 3, 4].map((item) => (
          <Child key={item} />
        ))}
      </Parent>
    </div>
  );
};

Parent Component:

import React, { FC, Children, cloneElement } from 'react';

interface IProps {
  children: React.ReactNode;
}
const Parent: FC<IProps> = ({ children }) => {
  const handleChange = (value: string) => {
    console.log('VALUE: ', value);
  };
  return (
    <div>
      {Children.map(children, (child, index) =>
        cloneElement(child as React.ReactElement, {
          handleChange: handleChange,
        })
      )}
    </div>
  );
};
  • Related