Search code examples
reactjstypescriptreact-hooksevent-handlingreact-functional-component

Listening to events fired from Children component in Parent Component in React


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


Solution

  • 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>
    )}