react 컴포넌트 export 주의점

이윤희·2025년 1월 4일

React/Next 일기

목록 보기
9/52

배경

쇼핑몰 구현 중...

Detail 페이지를 따로 컴포넌트로 만들었고, 그 컴포넌트를 다른 파일로 분리하고 import 해 왔다.
근데 분명 export도 잘? 한? 것 같고 import도 했는데...

내가 <Detail / > 을 넣었더니 expected a string or class/function 이라는 에러가 발생했다.

경로도 확인해 봤는데 경로에는 문제가 없었다.
그럼 뭐가 문제야?

App.js

import Detail from "./Detail.js";

function App() {

  return (
    //중략
    
        <Route path="/detail" element={Detail} />
        {/* Detail로 그냥 import했을때 <Detail /> 이렇게 넣기 가능!!!!
        어? 왜지? 내가 Detail 로 쓰면 되는데 <Detail />은 오류가 뜬다. */}
  );
}

Detail.js

function Detail() {
  return (
    <div className="container">
      <div className="row">
        <div className="col-md-6">
          <img
            src="https://codingapple1.github.io/shop/shoes1.jpg"
            width="100%"
          />
        </div>
        <div className="col-md-6">
          <h4 className="pt-5">상품명</h4>
          <p>상품설명</p>
          <p>120000</p>
          <button className="btn btn-danger">주문하기</button>
        </div>
      </div>
    </div>
  );
}

export default Detail();

그래서 ChatGPT한테 물어봤다.

그리고 내가 한 치명적인 실수를 발견...

요약하자면, export 할 때 함수 이름으로 내보냈어야 하는데 () 로 내보내서 문제가 생긴 것이다!!!

export default Detail (O)
export default Detail() (X)

()로 내보냈기 때문에 함수를 호출하고 그 결괏값을 반환하는 거였다...
때문에 함수 자체가 아니라 결괏값을 반환 -> 원래 받아야 하는 컴포넌트가 아닌 unexpected 무언가를 받게 됨.

오늘의 교훈 : 내보내기 할 때는 함수의 이름!!! 만 내보낸다.


GPT

당신이 겪고 있는 문제는 Detail 컴포넌트를 element에 올바르게 전달하지 못한 데에서 발생합니다.

1. 문제의 원인

Detail.js에서 export default Detail();로 내보내고 있습니다. 여기서 Detail()컴포넌트를 실행한 결과를 반환합니다. React는 element 속성으로 컴포넌트를 전달받기를 기대하지만, 여기서는 실행된 컴포넌트의 반환값 (JSX)를 전달하게 된 것입니다.

이로 인해 다음과 같은 문제가 발생합니다:

  • <Detail />와 같이 컴포넌트를 JSX로 사용하는 경우, React는 실행되지 않은 컴포넌트 자체를 필요로 합니다. 하지만 export default Detail();로 컴포넌트를 내보냈기 때문에 실제로는 JSX 반환값을 가져오므로 오류가 발생합니다.
  • Detail을 그대로 사용하면 React는 이를 일반적으로 실행된 JSX로 간주하기 때문에 문제가 없는 것처럼 보이지만, 이건 올바른 방식이 아닙니다.

2. 정확한 컴포넌트 내보내기 방식

React 컴포넌트는 반드시 컴포넌트 정의 자체export해야 합니다. 즉, Detail을 실행하지 말고 함수로 내보내야 합니다.

수정된 Detail.js는 다음과 같아야 합니다:

function Detail() {
  return (
    <div className="container">
      <div className="row">
        <div className="col-md-6">
          <img
            src="https://codingapple1.github.io/shop/shoes1.jpg"
            width="100%"
          />
        </div>
        <div className="col-md-6">
          <h4 className="pt-5">상품명</h4>
          <p>상품설명</p>
          <p>120000</p>
          <button className="btn btn-danger">주문하기</button>
        </div>
      </div>
    </div>
  );
}

export default Detail; // 실행하지 않고 함수 자체를 export

이렇게 하면 Detail을 컴포넌트로 사용하거나 JSX에서 <Detail />로 정상적으로 렌더링할 수 있습니다.


3. React Router에서 컴포넌트를 전달하는 방법

React Router의 <Route> 컴포넌트는 element 속성에 컴포넌트를 JSX로 전달해야 합니다. 이는 React Router가 내부적으로 컴포넌트를 렌더링할 때 사용하는 방식입니다. element={Detail}와 같은 형태로 작성하면 React는 이를 단순 값으로 간주하므로 동작이 다릅니다.

따라서 App.js에서 Route를 다음과 같이 작성해야 합니다:

import Detail from "./Detail.js";
import { BrowserRouter as Router, Routes, Route, useNavigate } from "react-router-dom";

function App() {
  let navigate = useNavigate();

  return (
    <Router>
      <Routes>
        {/* Detail 컴포넌트를 JSX로 전달 */}
        <Route path="/detail" element={<Detail />} />
      </Routes>
    </Router>
  );
}

export default App;

여기서 element={<Detail />}는 React Router가 Detail 컴포넌트를 JSX로 받아들여 올바르게 렌더링할 수 있게 합니다.


4. element={Detail}가 동작하는 경우가 있나요?

element={Detail}가 동작하는 상황은 React Router 버전 5 이전에는 가능했지만, React Router 6 이상에서는 반드시 JSX 형태로 전달해야 합니다. React Router 6에서는 element 속성이 JSX를 요구하도록 설계되었습니다.

만약 element={Detail}를 사용하려면 다음과 같이 변경해야 합니다:

<Route path="/detail" element={React.createElement(Detail)} />

React.createElement(Detail)는 JSX(<Detail />)와 동일한 역할을 합니다.


5. 정리

  1. Detail.js에서 export default Detail();가 아닌 export default Detail;로 컴포넌트를 내보내야 합니다.
  2. React Router의 <Route>에서 element 속성에 컴포넌트를 JSX 형태(<Detail />)로 전달해야 합니다.
  3. React Router 6 이상에서는 반드시 JSX 형태로 전달하도록 권장됩니다.

수정 후, 아래와 같은 코드로 작성해야 에러 없이 동작합니다:

Detail.js

function Detail() {
  return (
    <div className="container">
      <div className="row">
        <div className="col-md-6">
          <img
            src="https://codingapple1.github.io/shop/shoes1.jpg"
            width="100%"
          />
        </div>
        <div className="col-md-6">
          <h4 className="pt-5">상품명</h4>
          <p>상품설명</p>
          <p>120000</p>
          <button className="btn btn-danger">주문하기</button>
        </div>
      </div>
    </div>
  );
}

export default Detail;

App.js

import Detail from "./Detail.js";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";

function App() {
  return (
    <Router>
      <Routes>
        <Route path="/detail" element={<Detail />} />
      </Routes>
    </Router>
  );
}

export default App;

0개의 댓글