React

[React] mui bottom navigation 적용 및 Error 해결

배고픈개발자 2023. 2. 11. 15:55

https://mui.com/material-ui/react-bottom-navigation/

 

Bottom Navigation React component - Material UI

The Bottom Navigation bar allows movement between primary destinations in an app.

mui.com

페이지 하단에 mui 의 bottom navigationd 적용한 화면입니다.

mui 적용 및 useNavigate를 통해 페이지를 이동할 경우 버튼에 반영되지 않는 Error를 해결해 보겠습니다. 

import { Link } from "react-router-dom";
import { BottomNavigation, BottomNavigationAction } from "@mui/material";
import { useState } from "react";
import HomeIcon from "@mui/icons-material/Home";
import ContactPageIcon from "@mui/icons-material/ContactPage";
import LocalAtmIcon from "@mui/icons-material/LocalAtm";
import HistoryIcon from "@mui/icons-material/History";

// 원하는 Icon 을 import 해서 커스텀이 가능합니다.


const Footer = () => {

  const [selected, setSelected] = useState(0);

  return (
    <footer>
      <BottomNavigation
        sx={{ height: 80}}
        showLabels
        value={selected}
        onChange={(event, newValue) => {
          setSelected(newValue);
        }}
      >
      
     하단의 버튼을 누를 경우 onChange 이벤트가 발생하여 useState의 값을 변경합니다. 
     현재 하단에 4개의 link가 있고, 각각 0부터 3까지의 INDEX값을 갖습니다.
     예를 들어 Home 버튼을 누르게 되면 newValue는 0이 되고, setSelected로 selected 값을 0 으로 변경합니다. 
     
      
        <BottomNavigationAction 
          label="홈"
          icon={<HomeIcon sx={{ color: "F2E6C7" }} />}
          component={Link}
          to="/"
          id="icon"
        />
        <BottomNavigationAction
        
          label="마이페이지"
          icon={<ContactPageIcon sx={{ width: 30}}/>}
          component={Link}
          to="/mypage"
        />
        <BottomNavigationAction
          label="등록내역"
          icon={<HistoryIcon />}
          component={Link}
          to="/registration-detail"
        />
        <BottomNavigationAction
          label="코인"
          icon={<LocalAtmIcon />}
          component={Link}
          to="/cash"
        />
       	
        
     4개의 버튼에 icon과 label 및 해당 버튼을 눌렀을 경우 어떤url로 보내는지 적습니다.
       
      </BottomNavigation>
    </footer>
  );
};

export default Footer;

 

다음과 같이 작업하면 버튼을 클릭할 경우 state 값이 변경되며 해당 버튼에 불이 들어 오게 됩니다. 

홈은 0, 마이페이지는 1, 등록내역은 2, 코인은 3의 value를 가지게 됩니다. 

 

하지만 위의 방법을 사용하게 되면 버튼을 사용하지 않고 페이지를 이동하면 버튼에 반영되지 않게 됩니다.

예를 들면 useNavigate를 사용하거나 새로고침을 하게 되면 0번 인덱스인 Home 화면에 불이 들어 오게 됩니다. 

 

 

 

 

이를 해결하기 위해 인덱스를 사용하는 것이 아닌 url path를 사용합니다.

bottom navigation이 mount 될 때 window.location.pathname을 통해 현재 url의 path를 가져 옵니다.

selected 값을 url path로 설정하면 버튼을 클릭하지 않고 페이지로 이동하게 돼도 해당 버튼에 불이 들어오게 됩니다.

각각의 버튼의 value 값을 해당하는 url path 로 변경합니다. 

 

import { Link } from "react-router-dom";
import { BottomNavigation, BottomNavigationAction } from "@mui/material";
import { useState } from "react";
import HomeIcon from "@mui/icons-material/Home";
import ContactPageIcon from "@mui/icons-material/ContactPage";
import LocalAtmIcon from "@mui/icons-material/LocalAtm";
import HistoryIcon from "@mui/icons-material/History";

const Footer = () => {


  
  const pathname = window.location.pathname
  const [selected, setSelected] = useState(pathname);

  return (
    <footer>
      <BottomNavigation
        sx={{ height: 80}}
        showLabels
        value={selected}
        onChange={(event, newValue) => {
          setSelected(newValue);
        }}
      >
        <BottomNavigationAction 
          label="홈"
          icon={<HomeIcon sx={{ color: "F2E6C7" }} />}
          component={Link}
          to="/"
          id="icon"
          value = "/"
        />
        <BottomNavigationAction
          label="마이페이지"
          icon={<ContactPageIcon sx={{ width: 30}}/>}
          component={Link}
          to="/mypage"
          value = "/mypage"
        />
        <BottomNavigationAction
          label="등록내역"
          icon={<HistoryIcon />}
          component={Link}
          to="/registration-detail"
          value = "/registration-detail"
        />
        <BottomNavigationAction
          label="코인"
          icon={<LocalAtmIcon />}
          component={Link}
          to="/cash"
          value = "/cash"
        />
      </BottomNavigation>
    </footer>
  );
};

export default Footer;

최종 코드