Home > Software engineering >  Where to declare the handler function in child to get the clicked item details
Where to declare the handler function in child to get the clicked item details

Time:09-28

I want the category details in the parent categoryHandler function from the child component. I don't know where to place this props.categoryHandler function in the child component so that when it is clicked I should get the details to the parent categoryHandler function.

PARENT COMPONENT:

const categoryHandler = (catg) => {
  console.log(catg);
}

<div className="categoryBox">
  <Category categories={categories} categoryHandler={() => categoryHandler} />
</div>

CHILD COMPONENT:

export default function Category({ categories }) {
    if (categories.length) {
        const menu = recursiveMenu(categories);
        return menu.map((item, key) => <MenuItem key={key} item={item} />);
    } else {
        return <div>No Menus</div>
    }
}

const MenuItem = ({ item }) => {
    const Component = hasChildren(item) ? MultiLevel : SingleLevel;
    return <Component item={item} />;
};

const SingleLevel = ({ item }) => {
    return (
        <ListItem button>
            <ListItemText className="category-link child" primary={item.title} />
        </ListItem>
    );
};

const MultiLevel = ({ item }) => {
    const { items: children } = item;
    const [open, setOpen] = useState(false);

    const handleClick = () => {
        setOpen((prev) => !prev);
    };

    return (
        <React.Fragment>
            <ListItem button onClick={handleClick}>
                <ListItemText className="category-link parent" primary={item.title} />
                {open ? <ExpandLess /> : <ExpandMore />}
            </ListItem>
            <Collapse in={open} timeout="auto" unmountOnExit>
                <List component="div" disablePadding>
                    {children.map((child, key) => (
                        <MenuItem key={key} item={child} />
                    ))}
                </List>
            </Collapse>
        </React.Fragment>
    );
};

CodePudding user response:

Your approach in the code is right, just you have to modify two thing to achieve what you are expecting.

  1. In the parent component you have to modify passing the function as a props like this:

    categoryHandler={categoryHandler}

  2. In the child component you have to catch the function while destructuring the props and call in on the both list item with the single item as function parameter:

  • add the function in props destructuring and pass the function as another props to MenuItem
export default function Category({ categories, categoryHandler }) {
    if (categories.length) {
        const menu = recursiveMenu(categories);
        return menu.map((item, key) => <MenuItem categoryHandler={categoryHandler} key={key} item={item} />);
    } else {
        return <div>No Menus</div>
    }
}
  • Now again pass the function props to Single And MultiLevel List and call the function on both place:
const MenuItem = ({ item, categoryHandler }) => {
    const Component = hasChildren(item) ? MultiLevel : SingleLevel;
    return <Component item={item} categoryHandler={categoryHandler} />;
};


const SingleLevel = ({ item, categoryHandler }) => {
    return (
        <ListItem button onClick={handleClick}>
            <ListItemText className="category-link child" primary={item.title} />
        </ListItem>
    );
};

const MultiLevel = ({ item, categoryHandler}) => {
    const { items: children } = item;
    const [open, setOpen] = useState(false);

    const handleClick = () => {
        setOpen((prev) => !prev);
    };

    return (
        <React.Fragment>
            <ListItem button onClick={handleClick}>
                <ListItemText className="category-link parent" primary={item.title} />
                {open ? <ExpandLess /> : <ExpandMore />}
            </ListItem>
            <Collapse in={open} timeout="auto" unmountOnExit>
                <List component="div" disablePadding>
                    {children.map((child, key) => (
                        <MenuItem key={key} item={child} />
                    ))}
                </List>
            </Collapse>
        </React.Fragment>
    );
};

This solution should work fine!

CodePudding user response:

When you call your function passed as a prop, you can pass data from a child to parent component.

Parent Component:

const categoryHandler = (catg) => {
  console.log(catg);
}

<div className="categoryBox">
  <Category categories={categories} categoryHandler={categoryHandler} />
</div>

Child Component:

export default function Category(props) {
    props.categoryHandler(data);
}

CodePudding user response:

You can need to pass the parameter to the function in your parent component like this:

<Category categories={categories} categoryHandler={categoryHandler} />

You need to pass the prop categoryHandler all the way to the SingleLevel like this:

categoryHandler={categoryHandler}

You can need to add onClick to the ListItem in your SingleLevel component with item parameter like this:

<ListItem button onClick={() => categoryHandler(item)}>

You can take a look at this sandbox for a live working example of this solution.

  • Related