반응: 소품으로 구성 요소 VS 요소

이 기사에서는 다른 구성 요소/요소를 소품으로 효과적으로 받아들이는 구성 요소를 만드는 방법을 살펴보겠습니다.

왜 필요한가요?
우리는 이미 children 소품이 있는데 왜 이것이 필요한가요?

일반적으로 자식은 텍스트인 버튼 구성 요소를 만들고 싶다고 상상해 보십시오. 그리고 이제 우리는 아이콘에 대한 또 다른 자식이 필요합니다. 여기에서 소품으로 구성 요소/요소가 유용합니다. 분리된 부모에 자식을 가질 수 있습니다.

구성 요소로 전달하는 것과 요소로 전달하는 두 가지 방법이 있습니다.

술어:
1) 컴포넌트: JSX 요소를 반환하는 함수
2) 요소: JSX 요소

결국 어떤 패턴을 사용해야 하는지 명확한 답을 얻게 될 것입니다.

1) 구성 요소로 전달

const A = ({ component }: { component: () => JSX.Element }) => {
  const Component = component;
  return <Component />;
};

const B = () => {
  return <div>as component</div>;
};

export default function App() {
  return <A component={B} />;
}


codesandbox

지금까지는 좋았지만 어떤 상태를 B에 전달해야 한다면 어떻게 해야 할까요?

import { useState } from "react";

const A = ({ component }: { component: () => JSX.Element }) => {
  const Component = component;
  return <Component />;
};

const B = ({ count }: { count: number }) => {
  return <div>{`as component with state:${count}`}</div>;
};

export default function App() {
  const [count, setCount] = useState(0);
  return (
    <>
      <A component={() => <B count={count} />} />
      <button
        onClick={() => {
          setCount((count) => count + 1);
        }}
      >
        increase the count
      </button>
    </>
  );
}


codesandbox

그렇게하는 것 같습니다. 작동하고 있습니다.

그러나 () => <B count={count} />를 자세히 살펴보십시오. 뭔가 잘못되었습니다. 무엇인지 짐작할 수 있습니까?

이제 동일한 코드를 다시 시도하지만 이번에는 B에 useEffect를 추가하여 마운트 및 마운트 해제 이벤트를 추적합니다.

import { useEffect, useState } from "react";

const A = ({ component }: { component: () => JSX.Element }) => {
  const Component = component;
  return <Component />;
};

const B = ({ count }: { count: number }) => {
  useEffect(() => {
    console.log("mounted");
    return () => {
      console.log("unmounted");
    };
  }, []);
  return <div>{`as component with state:${count}`}</div>;
};

export default function App() {
  const [count, setCount] = useState(0);
  return (
    <>
      <A component={() => <B count={count} />} />
      <button
        onClick={() => {
          setCount((count) => count + 1);
        }}
      >
        increase the count
      </button>
    </>
  );
}


codesandbox

이제 콘솔을 열고 카운트를 늘리면 다음과 같이 표시됩니다.


이는 모든 재렌더링(함수 재실행)에 대해 () => <B count={count} /> 익명 함수이기 때문에 새 참조를 반환하기 때문입니다. 따라서 React는 이를 다른 구성 요소라고 생각하고 다시 마운트합니다.

우리가 이것을 해결할 수 있습니까? 해결책은 간단합니다. 대신 요소로 전달하면 됩니다.

2) 요소로 전달

import { useEffect, useState } from "react";

const A = ({ element }: { element: JSX.Element }) => {
  return element;
};

const B = ({ count }: { count: number }) => {
  useEffect(() => {
    console.log("mounted");
    return () => {
      console.log("unmounted");
    };
  }, []);
  return <div>{`as component with state:${count}`}</div>;
};

export default function App() {
  const [count, setCount] = useState(0);
  return (
    <>
      <A element={<B count={count} />} />
      <button
        onClick={() => {
          setCount((count) => count + 1);
        }}
      >
        increase the count
      </button>
    </>
  );
}


codesandbox


보시다시피 구성 요소는 두 번만 마운트됩니다**

즉, 요소로 전달하는 것이 우리가 사용해야 하는 패턴입니다.

**React 18 마운트 이벤트는 dev 환경에서 두 번 실행됩니다.

좋은 웹페이지 즐겨찾기