티스토리 뷰

728x90
반응형

useState & Record(type script)를 활용한 상태 관리

import { useState } from "react";

function Menu() {
    const [toggleSubMenu, setToggleSubMenu] = useState<Record<string, boolean>>({});

    const handleToggleSubMenu = (menuName: string) => {
        setToggleSubMenu((prevState) => ({
            ...prevState,
            [menuName]: !prevState[menuName],
        }));
    }

    return (
        <nav id="menu">
            <header className="major">
                <h2>Menu</h2>
            </header>
            <ul>
                <li><a href="index.html">Homepage</a></li>
                <li><a href="generic.html">Generic</a></li>
                <li><a href="elements.html">Elements</a></li>
                <li>
                    <span className={toggleSubMenu['submenu1'] ? 'opener active' : 'opener'} onClick={() => handleToggleSubMenu('submenu1')}>Submenu</span>
                    <ul>
                        <li><a href="#">Lorem Dolor</a></li>
                        <li><a href="#">Ipsum Adipiscing</a></li>
                        <li><a href="#">Tempus Magna</a></li>
                        <li><a href="#">Feugiat Veroeros</a></li>
                    </ul>
                </li>
                <li><a href="#">Etiam Dolore</a></li>
                <li><a href="#">Adipiscing</a></li>
                <li>
                    <span className={toggleSubMenu['submenu2'] ? 'opener active' : 'opener'} onClick={() => handleToggleSubMenu('submenu2')}>Another Submenu</span>
                    <ul>
                        <li><a href="#">Lorem Dolor</a></li>
                        <li><a href="#">Ipsum Adipiscing</a></li>
                        <li><a href="#">Tempus Magna</a></li>
                        <li><a href="#">Feugiat Veroeros</a></li>
                    </ul>
                </li>
                <li><a href="#">Maximus Erat</a></li>
                <li><a href="#">Sapien Mauris</a></li>
                <li><a href="#">Amet Lacinia</a></li>
            </ul>
        </nav>
    );
}

export default Menu

useReducer를 활용한 상태 관리

import { useState, useReducer } from "react";

type State = Record<string, boolean>;
type Action = { type: "toggle"; menuName: string };

function reducer(state: State, action: Action): State {
    switch (action.type) {
        case "toggle":
            return {
                ...state,
                [action.menuName]: !state[action.menuName],
            };
        default:
            throw new Error("Unknown action type");
    }
}


function Menu() {
    const [toggleSubMenu, dispatch] = useReducer(reducer, {});

    return (
        <nav id="menu">
            <header className="major">
                <h2>Menu</h2>
            </header>
            <ul>
                <li><a href="index.html">Homepage</a></li>
                <li><a href="generic.html">Generic</a></li>
                <li><a href="elements.html">Elements</a></li>
                <li>
                    <span className={toggleSubMenu['submenu1'] ? 'opener active' : 'opener'} onClick={() => dispatch({ type: "toggle", menuName: "submenu1" })}>Submenu</span>
                    <ul>
                        <li><a href="#">Lorem Dolor</a></li>
                        <li><a href="#">Ipsum Adipiscing</a></li>
                        <li><a href="#">Tempus Magna</a></li>
                        <li><a href="#">Feugiat Veroeros</a></li>
                    </ul>
                </li>
                <li><a href="#">Etiam Dolore</a></li>
                <li><a href="#">Adipiscing</a></li>
                <li>
                    <span className={toggleSubMenu['submenu2'] ? 'opener active' : 'opener'} onClick={() => dispatch({ type: "toggle", menuName: "submenu2" })}>Another Submenu</span>
                    <ul>
                        <li><a href="#">Lorem Dolor</a></li>
                        <li><a href="#">Ipsum Adipiscing</a></li>
                        <li><a href="#">Tempus Magna</a></li>
                        <li><a href="#">Feugiat Veroeros</a></li>
                    </ul>
                </li>
                <li><a href="#">Maximus Erat</a></li>
                <li><a href="#">Sapien Mauris</a></li>
                <li><a href="#">Amet Lacinia</a></li>
            </ul>
        </nav>
    );
}

export default Menu

Sub Component 활용한 상태 관리

import SubMenu from "./SubMenu";

function Menu() {
    return (
        <nav id="menu">
            <header className="major">
                <h2>Menu</h2>
            </header>
            <ul>
                <li><a href="index.html">Homepage</a></li>
                <li><a href="generic.html">Generic</a></li>
                <li><a href="elements.html">Elements</a></li>
                <SubMenu title="Submenu">
                    <li><a href="#">Lorem Dolor</a></li>
                    <li><a href="#">Ipsum Adipiscing</a></li>
                    <li><a href="#">Tempus Magna</a></li>
                    <li><a href="#">Feugiat Veroeros</a></li>
                </SubMenu>
                <li><a href="#">Etiam Dolore</a></li>
                <li><a href="#">Adipiscing</a></li>
                <SubMenu title="Another Submenu">
                    <li><a href="#">Lorem Dolor</a></li>
                    <li><a href="#">Ipsum Adipiscing</a></li>
                    <li><a href="#">Tempus Magna</a></li>
                    <li><a href="#">Feugiat Veroeros</a></li>
                </SubMenu>
                <li><a href="#">Maximus Erat</a></li>
                <li><a href="#">Sapien Mauris</a></li>
                <li><a href="#">Amet Lacinia</a></li>
            </ul>
        </nav>
    );
}

export default Menu






import { useState } from "react";

function SubMenu({title, children}: {title:string, children:React.ReactNode}) {
    const [isOpen, setIsOpen] = useState<boolean>(false);
    const toggleSubMenu = () => {
        setIsOpen(!isOpen);
    };

    return (
        <li>
            <span className={isOpen ? "opener active" : "opener"} onClick={toggleSubMenu}>
                {title}
            </span>
            <ul>{children}</ul>
        </li>
    );
}

export default SubMenu
728x90
반응형