Undergrad Research

[React, TroubleShooting] ThemeProvider은 무엇일까?

Jay_J 2024. 7. 16. 09:12

이번에 프로젝트를 진행하던 도중 문제가 생겼다.

 

텍스트만 있는 버튼보단, 옆에 아이콘도 같이 넣어주면 더 좋아보일까 싶어 버튼 옆에 아이콘을 추가 하려고 했다. 그래서 이번엔 MUI를 사용해 버튼을 넣으려고 했다. 하지만, 아래와 같이 버튼 아이콘을 넣으면 자꾸 이러한 에러가 떴다. 콘솔문을 보면 useContext에서 null값을 읽어서 발생하는 오류 같은데, useContext는 내가 사용한 기억도 없고, 프로젝트 전체를 뒤져봐도 useContext는 찾을 수 없었다.

 


Cannot read properties of null (reading 'useContext') TypeError: Cannot read properties of null (reading 'useContext') at Object.useContext (https://crescendo.cs.vt.edu/static/js/bundle.js:76455:25) at useTheme (https://crescendo.cs.vt.edu/static/js/bundle.js:71137:59) at useTheme (https://crescendo.cs.vt.edu/static/js/bundle.js:71045:77) at useThemeProps (https://crescendo.cs.vt.edu/static/js/bundle.js:71101:68) at useThemeProps (https://crescendo.cs.vt.edu/static/js/bundle.js:67972:79) at SvgIcon (https://crescendo.cs.vt.edu/static/js/bundle.js:66741:82) at renderWithHooks (https://crescendo.cs.vt.edu/static/js/bundle.js:39186:22) at updateForwardRef (https://crescendo.cs.vt.edu/static/js/bundle.js:42435:24) at beginWork (https://crescendo.cs.vt.edu/static/js/bundle.js:44496:20) at HTMLUnknownElement.callCallback (https://crescendo.cs.vt.edu/static/js/bundle.js:29442:18)

import AutoStoriesOutlinedIcon from '@mui/icons-material/AutoStoriesOutlined';

                    <div style={{ marginTop: '2rem', textAlign: 'center' }}>
                        <Button onClick={handleClickCourses} className="custom-button mb-4">
                        <AutoStoriesOutlinedIcon />
                            Courses</Button>
                        <Button onClick={handleClickManageStudents} className="custom-button mb-4">Manage Students</Button>
                        <Button variant="light" className="custom-button mb-4">Settings</Button>
                    </div>

 

도대체 저 버튼 아이콘이 뭐길래 런타임 에러가 뜨는지... 구글에 검색을 해보았다. 검색을 해보니 여러가지 경우가 있었지만, 내가 발견한 케이스는 다음과 같다.

 

"MaterialUI(MUI)를 사용하려면 ThemeProvider 안에 하위 디렉토리를 감싸야 한다"

 

이 말이 뭔가 싶어 공식 문서를 뒤져보았다.


`ThemeProvider`의 역할
`ThemeProvider`는 Material-UI에서 제공하는 테마를 React 컴포넌트 트리에 전달하는 역할을 한다. 이 테마는 색상, 타이포그래피, 간격 등 여러 스타일 속성을 포함하며, MUI 컴포넌트들이 이 테마를 참고하여 스타일을 적용한다.

왜 `ThemeProvider`가 필요한가?
Material-UI 컴포넌트들은 기본적으로 테마를 필요로 한다. 테마가 없으면 컴포넌트들이 어떻게 스타일링 되어야 할지 알지 못하기 때문에 오류가 발생할 수 있다. 특히, MUI 아이콘 컴포넌트들은 테마와 긴밀하게 연관되어 있으며, 테마가 없으면 올바르게 동작하지 않는다.

예시: `AutoStoriesOutlinedIcon`
`AutoStoriesOutlinedIcon`과 같은 MUI 아이콘 컴포넌트는 테마에 접근하여 색상이나 크기 등의 스타일 속성을 가져온다. `ThemeProvider`를 사용하지 않으면 이러한 스타일 속성을 찾을 수 없게 되고, 결과적으로 컴포넌트가 제대로 렌더링되지 않는다.

테마 적용 전후의 차이

테마 적용 전 (`ThemeProvider` 없이):

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<LoginPage />} />
        <Route path="/Dashboard" element={<Dashboard />} />
        <Route path="/FeedbackPage" element={<FeedbackPage />} />
        <Route path="/GiveFeedback" element={<GiveFeedback />} />
        <Route path="/FacultyDashboard" element={<FacultyDashboard />} />
        <Route path="/ManageStudents" element={<ManageStudents />} />
        <Route path="/course/:courseId" element={<CourseDetails />} />
        <Route path="/Courses" element={<Courses />} />
      </Routes>
    </BrowserRouter>
  );
}


이 상태에서는 MUI 컴포넌트들이 테마를 참조할 수 없기 때문에, `AutoStoriesOutlinedIcon`과 같은 컴포넌트에서 오류가 발생할 수 있다.

테마 적용 후 (`ThemeProvider` 추가):

import { ThemeProvider, createTheme } from '@mui/material/styles';

// 테마 설정
const theme = createTheme({
  palette: {
    primary: {
      main: '#1976d2',
    },
    secondary: {
      main: '#dc004e',
    },
  },
  typography: {
    fontFamily: 'Roboto, Arial, sans-serif',
  },
});

function App() {
  return (
    <ThemeProvider theme={theme}>
      <BrowserRouter>
        <Routes>
          <Route path="/" element={<LoginPage />} />
          <Route path="/Dashboard" element={<Dashboard />} />
          <Route path="/FeedbackPage" element={<FeedbackPage />} />
          <Route path="/GiveFeedback" element={<GiveFeedback />} />
          <Route path="/FacultyDashboard" element={<FacultyDashboard />} />
          <Route path="/ManageStudents" element={<ManageStudents />} />
          <Route path="/course/:courseId" element={<CourseDetails />} />
          <Route path="/Courses" element={<Courses />} />
        </Routes>
      </BrowserRouter>
    </ThemeProvider>
  );
}


이 상태에서는 모든 MUI 컴포넌트들이 `ThemeProvider`로부터 테마를 참조할 수 있기 때문에, `AutoStoriesOutlinedIcon`과 같은 컴포넌트들이 올바르게 동작한다.

요약
- `ThemeProvider`는 MUI 컴포넌트들이 참조할 수 있는 테마를 제공하며, 이를 통해 일관된 스타일을 적용한다.
- `ThemeProvider`가 없으면 MUI 컴포넌트들이 필요한 스타일 정보를 얻지 못해 오류가 발생할 수 있다.
- `ThemeProvider`를 추가함으로써 MUI 컴포넌트들이 올바르게 스타일링되고, 정상적으로 동작하게 된다.

이렇게 ThemeProvider를 추가하니 아래와 같이 버튼 옆에 아이콘이 보인다.

또 한가지, 

ThemeProvider 컴포넌트는 Routes의 자식 컴포넌트가 될 수 없다. 모든 <Routes>의 자식은 <Route> 또는 <React.Fragment> 여야 한다.