Search code examples
reactjsfunctioncomponents

React trigger function inside component


I am working on a dynamic sidebar which maps the menu items based on which user is logged in.

the trouble I am having is triggering a function inside a functional component. my component looks like this -

popout.js

import React from 'react'

export default function PopOut({listitems}) {
const togglePopout =()=>{
console.log("Popout")
}
    return (
        listitems.map((child) => {
                <div>{child.label}</div>;
            });
    )
}

menu.js

import PopOut from "./popout.js"


import React from 'react'

export default function menu() {

const menuitems = [
{
    label: "Menu 1",
    children: [{ label: "Dashboard" }, { label: "item2" }],
}
{
    label: "Menu 2",
    children: [{ label: "People" }, { label: "item3" }],
}
{
    label: "Menu 3",
    children: [{ label: "Payments" }, { label: "item4" }],
}
];

    return (
        {
// here I want to click the menu and trigger the togglePopout function inside the component. 
    menuitems.map((item) => {
        <div onClick={()=>togglePopout()}>{item.label}</div>;
        {
         <Popout listItems={item.children}/>
            
        }
    });
}

    )
}

I want to click the menu and trigger the togglePopout function inside the component

as always any help is greatly appreciated


Solution

  • You can't do it like that with react. React is declarative which means a component describes what should be rendered given the state and props of the component. What you are trying to do is how you would do it with e.g. jQuery. What you need to do is set the items as component state and render it accordingly. Returning jsx from a handler won't do anything to the rendered output of a component.

    A possible solution would be to store inside of the PopOut if it should show its children:

    const menuItems = [
        {
            label: "Menu 1",
            children: [{ label: "Dashboard" }, { label: "item2" }],
        },
        {
            label: "Menu 2",
            children: [{ label: "People" }, { label: "item3" }],
        },
        {
            label: "Menu 3",
            children: [{ label: "Payments" }, { label: "item4" }],
        },
    ];
    
    const PopOut = ({item}) => {
        const [isOpen, setIsOpen] = useState(false); // initially closed
        const toggle = () => setIsOpen(state => !state); // toggle open state 
    
        return (
            <div className="menu-item" onClick={toggle}>
                {item.label}
                {isOpen && item.children.map(child => (
                    <div>{child.label}</div>
                ))}
            </div>
        );
    }
    
    
    const Menu = () => (
        <div className="menu">
            {menuItems.map(item => <PopOut item={item} />)}
        </div>
    );