Mui 2장 - Tab 사용하기
포스트
취소

Mui 2장 - Tab 사용하기

Mui

Mui Tabs & Tab Tab API

Tabs 공식문서

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import * as React from 'react';
import Box from '@mui/material/Box';
import Tabs from '@mui/material/Tabs';
import Tab from '@mui/material/Tab';
import Typography from '@mui/material/Typography';
import {
  MemoryRouter,
  Route,
  Routes,
  Link,
  matchPath,
  useLocation,
} from 'react-router-dom';
import { StaticRouter } from 'react-router-dom/server';

function Router(props: { children?: React.ReactNode }) {
  const { children } = props;
  if (typeof window === 'undefined') {
    return <StaticRouter location="/drafts">{children}</StaticRouter>;
  }

  return (
    <MemoryRouter initialEntries={['/drafts']} initialIndex={0}>
      {children}
    </MemoryRouter>
  );
}

function useRouteMatch(patterns: readonly string[]) {
  const { pathname } = useLocation();

  for (let i = 0; i < patterns.length; i += 1) {
    const pattern = patterns[i];
    const possibleMatch = matchPath(pattern, pathname);
    if (possibleMatch !== null) {
      return possibleMatch;
    }
  }

  return null;
}

function MyTabs() {
  // You need to provide the routes in descendant order.
  // This means that if you have nested routes like:
  // users, users/new, users/edit.
  // Then the order should be ['users/add', 'users/edit', 'users'].
  const routeMatch = useRouteMatch(['/inbox/:id', '/drafts', '/trash']);
  const currentTab = routeMatch?.pattern?.path;

  return (
    <Tabs value={currentTab}>
      <Tab label="Inbox" value="/inbox/:id" to="/inbox/1" component={Link} />
      <Tab label="Drafts" value="/drafts" to="/drafts" component={Link} />
      <Tab label="Trash" value="/trash" to="/trash" component={Link} />
    </Tabs>
  );
}

function CurrentRoute() {
  const location = useLocation();

  return (
    <Typography variant="body2" sx= color="text.secondary">
      Current route: {location.pathname}
    </Typography>
  );
}

export default function TabsRouter() {
  return (
    <Router>
      <Box sx=>
        <Routes>
          <Route path="*" element={<CurrentRoute />} />
        </Routes>
        <MyTabs />
      </Box>
    </Router>
  );
}

Tab 사용하기

  • 단일 페이지로 만드려고 계획하던 중 Nav bar에서 항목을 클릭했을 때, 항목에 연결된 컴포넌트를 보여주기 위한 탭이 필요했다.
  • 탭이나 Nav에 관한 여러 항목을 찾아보던 중 내가 사용하고자 하는 디자인과 기능에 적합한 것이 Tab이었다.
  • 코드 설명은 다음과 같다.
    1. 탭에 해당하는 리스트를 정한다.(url명, ex: Home = Home)
    2. 리액트 라우터를 사용하여 주솟값이 변경될 떄마다 이에 해당하는 리스트의 탭과 일치시킨다.
    3. 탭을 클릭할 시에도 이에 해당하는 라우터로 연결한다.
  • 위 방식은 Router로 해당하는 컴포넌트 페이지로 연결하지만, 내가 필요한 것은 단일 페이지기 때문에 라우터를 제외하고 해당 탭을 클릭했을 때 클릭한 리스트와 일치하는 id를 가진 컴포넌트를 화면에 보여주기로 했다.

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
const routeMatch = useRouteMatch(["/Home", "/About", "/Skills", "/Experience"]);

const currentTab = routeMatch;

const scrollHandler = (e: string) => {
  document.getElementById(e)?.scrollIntoView({
    behavior: "smooth",
  });
};

return (
  <Tabs
    value={currentTab}
    sx={
      {
        // "& .MuiTabs-indicator": { backgroundColor: "transparent" },
        // "& .Mui-selected": { color: "purple" },
      }
    }
  >
    <Tab
      key={list}
      label={list.replace("/", "")}
      value={"/" + list}
      to={list}
      component={Link}
      onClick={() => scrollHandler(list)}
    />
  </Tabs>
);
1
2
3
4
// Main.tsx
export default function Index() {
  return <div id="Home">Example</div>;
}
  • TabHome을 클릭할 때 해당하는 아이디를 가진 컴포넌트로 scrollIntoView 할 수 있다.
  • TabTabs로 감싸져 있어야 하며, sx로 해당 스타일을 지정한다.

2024-01-16

custom 시 props

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { styled } from "mui/material";

export default function Example() {
  return (
    <Tab
      key={list}
      label={list.replace("/", "")}
      value={"/" + list}
      to={list}
      component={Link}
      onClick={() => scrollHandler(list)}
    />
  );
}
  • 위 코드는 Mui code sande box에 나와있는 예제이다.
  • 하지만 Mui Tab API에 들어가보면 to, component 속성이 없다.
  • Tab 컴포넌트를 커스텀 하려고 할 때, 문제가 발생했다.
1
2
3
4
5
6
7
8
9
10
11
12
return (
  <TabList
    key={list}
    label={list.replace("/", "")}
    value={"/" + list}
    to={list} // error
    component={Link} // error
    onClick={() => scrollHandler(list)}
  />
);

const TabList = styled(Tab)({});
  • 위처럼 커스텀 시 에러가 발생했는데, 이는 Tab API에 나와있는 속성대로 기본적으로 제공되는 속성이 아니기에 에러가 생긴 것이다.
  • 커스텀 시에만 에러가 발생한 이유는, 커스텀 시에는 Tab의 기본 속성만을 사용되기에 속성을 추가적으로 작성해줘야 했다.
1
2
3
4
5
6
7
8
type TabCustomPropsType = {
  to: string;
  component: React.ForwardRefExoticComponent<LinkProps & React.RefAttributes<HTMLAnchorElement>>;
}

const TabList = styled(Tab)<TabCustomPropsType>({
  ...
})

참고자료1 참고자료2

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.