TIL: 자체 내부에 반응 구성 요소를 포함할 수 있습니다.

최근에 내 Gatsby 사이트 중 하나의 게시물을 일반 마크다운에서 MDX 으로 변환했습니다. 이 과정에서 각 게시물의 목차를 렌더링하는 방식을 변경해야 했습니다. dangerouslySetInnerHTML 함수에 전달된 HTML 블록 대신, 이제 각각 레벨 2 제목을 나타내는 객체 배열로 작업하고 있습니다.

[
  {
    url: '#description',
    title: 'Description'
  },
  {
    url: '#layout',
    title: 'Layout'
  }
  // More headings here…
];

이러한 표제 목록을 렌더링하려면 Array.map() 메서드를 사용하여 반복할 수 있습니다.

<ul>
  {items.map(item => (
    <li key={item.title}>
      <a href={item.url}>{item.title}</a>
    </li>
  ))}
</ul>

한 수준의 제목만 렌더링하는 경우에는 잘 작동하지만 수준 3 제목도 표시하려면 어떻게 해야 할까요? 다행히 gatsby-plugin-mdx에서 제공하는 tableOfContents에는 중첩된 items 개체의 모든 하위 제목이 포함됩니다. 예를 들어

{
  url: '#markup',
  title: 'Markup',
  items: [
    {
      url: '#approach-1-heading-with-button',
      title: 'Approach 1: Heading with Button'
    },
    {
      url: '#approach-2-summary-and-details',
      title: 'Approach 2: Summary and Details'
    }
  ]
}

이 자식 제목을 어떻게 렌더링합니까? 한 가지 대답은 기존 루프 내부에 동일한 논리를 다시 중첩하는 것입니다.

const TableOfContents = ({ items }) => (
  <ul>
    {items.map(item => (
      <li key={item.title}>
        <a href={item.url}>{item.title}</a>
        {/* Begin nested loop */}
        {item.items && item.items.length > 0 && (
          <ul>
            {items.map(item => (
              <li key={item.title}>
                <a href={item.url}>{item.title}</a>
              </li>
            ))}
          </ul>
        )}
      </li>
    ))}
  </ul>
);

불행히도 이것은 다루기 힘들고 반복되기 시작할 뿐만 아니라 한계도 있습니다. h2, h3 및 h4s의 세 가지 수준의 표제를 렌더링하려면 어떻게 해야 할까요? 이것은 재귀를 사용하여 풀 수 있는 문제입니다. 목록 항목을 렌더링하기 위한 새 TableOfContentsItem 구성 요소를 만들면 자식을 렌더링해야 하는 경우 자체를 호출할 수 있는 기능을 제공할 수 있습니다.

const TableOfContentsItem = ({ item }) => {
  const nestedItems = (item.items || []).map(nestedItem => {
    return <TableOfContentsItem item={nestedItem} key={nestedItem.title} />;
  });

  return (
    <li key={item.title}>
      <a href={item.url}>{item.title}</a>
      {nestedItems.length > 0 && <ul>{nestedItems}</ul>}
    </li>
  );
};

필요한 경우 TableOfContentsItem 하위 항목을 반복하여 서로를 렌더링하는 방법TableOfContentsItem에 유의하십시오. TableOfContents 구성 요소는 이제 가장 바깥쪽ul 내부에 한 번만 포함하면 됩니다.

const TableOfContents = ({ items }) => (
  <ul>
    {items.map(item => (
      <TableOfContentsItem item={item} key={item.title} />
    ))}
  </ul>
);

이제 모든 수준의 중첩을 처리할 수 있습니다. 이 기술은 모든 종류의 복잡한 탐색에 유용하며 React뿐만 아니라 Nunjucks 또는 Twig 과 같은 언어에서 템플릿 매크로를 사용하여 동일한 패턴을 얻을 수 있습니다.

Iza GawrychUnsplash의 사진

좋은 웹페이지 즐겨찾기