일 년 전 · 이지현 님의 새로운 댓글
리액트 타입스크립트 obj[key] 에러
타입스크립트 이제 막 적용해보는 초보입니다.. 코드 내 monitorMenu[type].container 에서 [type]에 에러가 뜨는데 타입 지정이 잘못 된 건지 찾아봐도 원인을 모르겠습니다ㅜㅜ 물어볼 곳이 없어 질문합니다,,! 도움 부탁드립니다...ㅠㅠ // code import React, { useEffect, useState } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; import DashboardContainer from '../containers/DashboardContainer'; import IntegratedContainer from '../containers/IntegratedContainer'; interface IMonitorMenu { [key: string]: { container: string | JSX.Element; }; } const Monitor = () => { const user: any = []; const { type } = useParams<{ type?: string }>(); const navigate = useNavigate(); const [menu, setMenu] = useState('integrated'); const onClickMenu = (name: string) => { navigate(`/monitor/${name}`); }; const monitorMenu: IMonitorMenu = { integrated: { container: <IntegratedContainer /> }, dashboard: { container: <DashboardContainer /> }, }; return ( <div> ... <div>{monitorMenu[type].container}</div> </div> ); }; export default Monitor; // error ERROR in src/pages/Monitor.tsx:37:25 TS2538: Type 'undefined' cannot be used as an index type.
개발자
#react
#typescript
답변 1
댓글 1
조회 92
일 년 전 · 우엉김밥 님의 새로운 댓글
리액트 프로젝트 vite로 빌드후 서버에 배포시 cannot get...
react-router-dom 을 사용중에있습니다. vite로 빌드하고 서버에 올렸는데... 경로 이동시 cannot get 이 뜹니다. 찾아본결과 서버에서 요청 url을 찾아서 그렇다 , 모든 서버 요청을 /index.html로 리디엑션하도록 하면 된다고 하는데 혹시 vite에서 그런 설정을 할 수 있나요?
개발자
#vite
#react-router-dom
답변 1
댓글 1
조회 221
일 년 전 · 김태우 님의 답변 업데이트
모바일 뷰에서 팝업이, 뒤로가기 제스처를 취했을 때 이전 페이지로 넘어가지 않고 팝업만 닫히게 구현하고 싶어요.
안녕하세요. 이번에 웹뷰 뿐만 아니라 모바일 뷰까지 같이 개발을 진행하고 있는데, 팝업의 기능 구현에 어려움을 겪고 있어 질문을 남깁니다. 웹뷰 같은 경우는 바로 팝업을 닫을 수 있지만, 모바일 같은 경우에는 무심결에 뒤로가기 제스처를 통해서 팝업을 닫으려는 유저가 있을 수 있다고 생각합니다. 그래서 뒤로가기 제스처가 발동 시, 이전 페이지로 렌더링을 시도하는 것을 막고 해당 팝업을 unmount 시키고 싶은데 방법이 잘 생각나지 않네요. **개발환경은 프론트 (react) 입니다. 그냥 간단하게 생각한다면 모바일 뷰일 때를 dom 으로 감지 후에 해당 팝업이 mount 된 상태에서 navigation(-1) 같은 동작을 감지하여, 이전 페이지로 이동 대신 팝업을 unmount 시키게, useEffect 등으로 감시하면 될 것 같은데, 어떻게 구현해야 될까요? + 현재 react-router-dom v6.2를 사용하고 있는데, useBlocker를 활용하면 해결될 것 같습니다..! https://reactrouter.com/en/main/hooks/use-blocker
개발자
#react
#웹앱
#모바일앱
#팝업
#react-router-dom
답변 1
댓글 0
조회 588
일 년 전 · 민경배 님의 답변 업데이트
리액트 내비게이션 초기 데이터값 설정
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에 보이게 할수있는 방법 있을까요 ?
개발자
#react
답변 1
댓글 0
조회 113
일 년 전 · 거니 님의 답변 업데이트
react-router-dom v6에서 useNavigate의 replace:true속성과 window.location.replace()의 차이점
window.performance.getEntriesByType("navigation")[0]의 type이 back_forward인 경우에 뒤로가기로 진입했다는걸 파악하고 있었는데 페이지 이동시에 useNavigate의 replace:true 속성일 때는 해당 옵션이 안나오고 location.replace로 이동시에만 해당 옵션값으로 판별이 가능한데 두개 차이점이 존재하는걸까요,,?
개발자
#react
#react-router-dom
#location
답변 1
댓글 0
조회 412
2년 전 · 커리어리 AI 봇 님의 새로운 답변
리액트 라우팅을 이렇게 하는게 맞는지 모르겠습니다..
안녕하세요 독학 하고 있는 학생입니다.. 작은 프로젝트로 혼자서 홈페이지를 만들고 있습니다. 우선 로그인 페이지부터 만들고 있는데, 로그인페이지에는 아이디찾기 비밀번호찾기 등등 많은 페이지가 들어가더라구요.. 그래서 리액트 라우터를 공부하고 적용시켰습니다. 코드는 아래와 같습니다. 이렇게 해도 제가 원하는대로 로그인페이지에서 아이디 찾기 페이지로 이동하고 하는 것은 맞는데 App.js에 이렇게 주저리주저리 원하는 것을 다 넣어두면 나중에 전체적으로 페이지를 완성시켰을 때 App.js에 너무 방대한 내용이 들어가지않나..? 싶더라구요.. 그래서 중첩된 라우트도 찾아서 공부했는데 크흡..암만해도 적용이 안됩니다.. 그래서 그냥 이대로 홈페이지를 계속 만들어도 되는지,,아니면 저의 고민을 해결할 방법이 중첩된 라우트가 맞는지 알고싶습니다.. 맞다면 다시 공부해야겠죠 ㅜ.. 답변부탁드립니다 (_ _) import "./App.css"; import { Route, Routes } from "react-router-dom"; import WigTemplate from "./components/wigtemplate"; import FindId from "./components/findId"; import FindPwd from "./components/findPwd"; import SignIn from "./components/signIn"; import NotFound from "./components/notFound"; function App() { return ( <Routes> <Route path="/" element={<WigTemplate />} /> <Route path="/findId" element={<FindId />} /> <Route path="/findPwd" element={<FindPwd />} /> <Route path="/signIn" element={<SignIn />} /> <Route path="*" element={<NotFound />} /> </Routes> ); } export default App; ---------------------------------------------------------- import React from "react"; import styled from "styled-components"; import WigLoginButton from "./wigLoginButton"; import WigHeader from "./wigHeader"; import WigInput from "./wigInput"; import WigFind from "./wigFind"; const WigTemplateContainer = styled.div` height: 100vh; display: flex; align-items: center; justify-content: center; `; const WigTemplateBlock = styled.div` width: 500px; height: 600px; background: #d0ebff; border-radius: 80px; `; function WigTemplate() { return ( <WigTemplateContainer> <WigTemplateBlock> <WigHeader></WigHeader> <WigInput></WigInput> <WigFind></WigFind> <WigLoginButton></WigLoginButton> </WigTemplateBlock> </WigTemplateContainer> ); } export default WigTemplate; ------------------------------------------------------- import React from "react"; import styled from "styled-components"; import { RxDividerVertical } from "react-icons/rx"; import { Link } from "react-router-dom"; const FindBlock = styled.div` display: flex; justify-content: center; `; const ABlock = styled(Link)` color: black; font-size: 0.9rem; text-decoration: none; `; function WigFind() { return ( <FindBlock> <ABlock to="/findId">아이디 찾기</ABlock> <RxDividerVertical style={{ marginTop: "3px" }} /> <ABlock to="/findPwd">비밀번호 찾기</ABlock> <RxDividerVertical style={{ marginTop: "3px" }} /> <ABlock to="/signIn">회원가입</ABlock> </FindBlock> ); } export default WigFind;
개발자
#react
답변 2
댓글 3
조회 469
2년 전 · 정현수 님의 답변 업데이트
React-Router-Dom 경로 관련 질문 있습니다.
현재 제 App.jsx 파일은 아래 사진과 같습니다. 기능별로 url을 구분했는데, 사용되는 페이지가 매우 많고 보여지는 것도 달라 개별 페이지들이 모두 필요합니다. 그러다보니 App.jsx에서 너무 많은 모듈(페이지 컴포넌트)들을 다 가져와서 파일의 import 부분이 너무 길고 지저분해 보입니다..ㅠㅠ 혹시 이를 개선할 방법이 있을지 궁금합니다.
개발자
#react
#react-router-dom
답변 1
댓글 1
추천해요 3
조회 248