개발자

리액트 내비게이션 초기 데이터값 설정

2023년 11월 27일조회 92

import React, { useEffect, useState } from "react"; import { Link, useLocation } from "react-router-dom"; import { TbArrowBigUpFilled } from "react-icons/tb"; import useScroll from "../utils/useScroll"; import useProductsQuery from "../useProductsQuery"; const Nav = () => { const { isNavFixed } = useScroll(); const [activeButton, setActiveButton] = useState(0); const handleButtonClick = (index) => { setActiveButton(index); }; const categoryNames = { materials: "소재별 품목", purposes: "용도별 품목", }; const [isScrollMenuVisible, setScrollMenuVisible] = useState(false); const handleMouseEnter = () => { setScrollMenuVisible(true); }; const handleMouseLeave = () => { // console.log("마우스 이탈"); setScrollMenuVisible(false); }; const location = useLocation(); const isloginorsignup = location.pathname === "/login" || location.pathname === "/signup"; const { isLoading, isError, errorMessage, materials, purposes } = useProductsQuery(); const [hoveredOnedepth, setHoveredOnedepth] = useState(null); const [onedepthChildren, setOnedepthChildren] = useState([]); const [hoveredDivision, setHoveredDivision] = useState(null); const [twodepthDivision, setTwodepthDivision] = useState([]); const handleOnedepthMouseEnter = (item) => { setHoveredOnedepth(item); // console.log(setHoveredOnedepth) setOnedepthChildren(item.children); }; const handletwodepthMouseEnter = (child) => { setHoveredDivision(child); // console.log(setTwodepthDivision); setTwodepthDivision(child.divisions); // console.log(child.divisions); }; if (isLoading) return <>로딩 중...</>; if (isError) return <>{errorMessage}</>; return ( <> {!isloginorsignup ? ( <> {/* 대메뉴 */} <nav id="nav" className={`nav ${isNavFixed ? "fixed" : ""}`}> <div className="nav_wrap"> <div className="twobutton_wrap"> {["materials", "purposes"].map((category, index) => ( <Link type="button" className={`twobutton ${ activeButton === index ? "active" : "" }`} key={index} onClick={() => handleButtonClick(index)} to={`/${category}`} > {categoryNames[category]} </Link> ))} </div> {/* 내비게이션 1depth */} <div className="scrollnav"> <ul className="materialnav" style={{ display: activeButton === 0 ? "flex" : "none", }} > {materials.map((material) => ( <li key={material.id} className="materialnav_li" onMouseEnter={() => { handleOnedepthMouseEnter(material); handleMouseEnter(); }} onMouseLeave={handleMouseLeave} > <Link to="/">{material.name}</Link> </li> ))} </ul> <ul className="usagenav" style={{ display: activeButton === 1 ? "flex" : "none", }} > {purposes.map((purpose) => ( <li key={purpose.id} className="usagenav_li" onMouseEnter={() => { handleOnedepthMouseEnter(purpose); handleMouseEnter(); }} onMouseLeave={handleMouseLeave} > <Link to="/">{purpose.name}</Link> </li> ))} </ul> </div> <div className="call_wrap"> <div className="call"> <div className="call_title">견적 상담 · 문의 대표전화</div> <div className="top_button"> <TbArrowBigUpFilled className="top_icon" /> <p>TOP</p> </div> </div> </div> </div> </nav> {/* 2&3depth 호버 메뉴 */} <div className={`scrollmenu ${isScrollMenuVisible ? "show" : ""} ${ isNavFixed ? "fixed" : "" }`} style={{ visibility: isScrollMenuVisible ? "visible" : "hidden" }} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave} > {activeButton === 0 && ( <div className="scrollmenu_top"> <ul className="depth2_wrap"> {onedepthChildren.map((child) => ( <li key={child.id} className="depth2_menu" onMouseEnter={() => { handletwodepthMouseEnter(child); }} > <div className="depth2_menu_img_wrap"> <div className="depth2_menu_img"> <img src={child.images[0]._links.href} alt={child.name} /> </div> </div> <p>{child.name}</p> </li> ))} </ul> </div> )} <div className="scrollmenu_middle"> <div className="depth3_wrap"> {twodepthDivision.map((division) => ( <Link key={division.id} to="/" className="depth3_menu"> <span className="depth3_menu_img"> {/* images 속성이 없거나 비어 있어도 오류를 방지 */} {division.images && division.images.length > 0 && ( <img src={division.images[0]._links.href} alt={division.division_name} /> )} </span> <p>{division.division_name}</p> </Link> ))} </div> </div> <div className="scrollmenu_bottom"></div> </div> </> ) : null} </> ); }; export default Nav; 현재는 depth2_menu 호버해야만 depth3_menu가 보이는데 초기에 scrollmenu가 보일때부터 depth2_menu가 (onedepthChildren.map의 첫번째 순서의 데이터가) 호버되어있어 그에 매칭되는 division의 내용들이 depth3_menu에 보이게 할수있는 방법 있을까요 ?

이 질문이 도움이 되었나요?
'추천해요' 버튼을 누르면 좋은 질문이 더 많은 사람에게 노출될 수 있어요. '보충이 필요해요' 버튼을 누르면 질문자에게 질문 내용 보충을 요청하는 알림이 가요.
profile picture
익명님의 질문

답변 1

인기 답변

민경배님의 프로필 사진

안녕하세요! 자세하게 코드를 남겨주신덕에 호다닥 잘 살펴보고 왔습니다ㅎㅎㅎ 현재 주신 구조에서 ScrollMenu가 보이기 시작하는 시점은 material이나 purpose를 호버하는 시점으로 보이네요! 현재 코드를 유지하는 관점에서 가장 간단한 해결법으로는, handleOnedepthMouseEnter 핸들러 내에서 setOnedepthChildren을 해줌과 동시에 if (item.children.length > 0) handletwodepthMouseEnter(item.children[0]) 를 호출해주는 방법이 있을 수 있겠네요! 질문의 의도가 맞는지는 모르겠지만, 만약 activeButton이 1(purpose)일 경우 depth2를 건너뛰는게 목적이라면, usagenav_li의 onMouseEnter에서 바로 handletwodepthMouseEnter(purpose)를 호출해주는 것도 방법일 수 있습니다. 일단 코드를 유지하는 선에서 방식을 말씀 드리긴 했지만, 저의 개인적인 욕심(?)을 아주 약간 덧붙여 몇가지 리팩토링을 진행해주신다면 조금 더 좋은 코드가 될 수 있어보입니다! 1. 내부 변수 이름 개선 - 조금 더 시멘틱하고 통일된 스타일의 변수 / 핸들러 명을 지어주시면 유지보수 면에서 깔끔할 것 같습니다 2. activeButton 개선 - 카테고리 선택시 index보다는 enum(TS 사용시), 혹은 categoryNames오브젝트를 활용하여 관리해주신다면, 추후 카테고리의 추가나 순서 변화 등에 유연하게 대처 가능한 코드가 될 것 같습니다 3. depth1의 경우, style의 display속성을 통해 변환해주시는 것으로 보입니다. 이럴 경우, 렌더 트리에는 반영되지 않지만 DOM트리에는 두 컴포넌트 모두 반영되어 리소스 낭비 및 불필요한 리렌더가 예상되므로, 조건부 렌더 방식을 고려해보시는 것도 좋아보입니다. (레퍼런스: https://ssangq.netlify.app/posts/conditional-rendering-vs-diplay-none) 4. !isloginorsignup 일 경우 그냥 null로 early return 시켜버려도 깔끔할 것 같습니다 조금 욕심 부리다보니 글이 길어졌네요,,ㅎㅎㅎ 기획 의도나 스타일에 따라 해석이 달라질 수 있으니, 혹시 추가로 궁금하신 부분이나 답변의 핀트가 엇나간 부분이 있다면 편하게 알려주세요!

지금 가입하면 모든 질문의 답변을 볼 수 있어요!

현직자들의 명쾌한 답변을 얻을 수 있어요.

또는

이미 회원이신가요?

목록으로
키워드로 질문 모아보기

실무, 커리어 고민이 있다면

새로운 질문 올리기

지금 가입하면 모든 질문의 답변을 볼 수 있어요!