React 고급 구성 요소를 이용하여 빵 부스러기 내비게이션을 실현하는 예시

React 고급 구성 요소
React 고급 구성 요소는 수식이 필요한 React 구성 요소를 고급 함수로 감싸고 처리가 끝난 React 구성 요소를 되돌려줍니다.React 고급 구성 요소는 React 생태에서 매우 빈번하게 사용된다. 예를 들어react-router의withRouter와react-redux의connect 등 많은 API는 이런 방식으로 이루어진다.
React 고급 구성 요소 사용의 이점
작업 중에 우리는 자주 많은 기능이 비슷하다. 구성 요소 코드가 중복되는 페이지 수요가 있다. 보통 우리는 코드를 완전히 복제하는 방식으로 기능을 실현할 수 있지만 이렇게 하면 페이지의 유지 보수가 매우 나빠지고 모든 페이지의 같은 구성 요소에 대해 변경을 해야 한다.따라서 우리는 그 중의 공통된 부분을 받아들일 수 있다. 예를 들어 같은 조회 작업 결과, 구성 요소 밖의 같은 라벨 패키지 등을 추출하여 하나의 단독 함수를 만들고 서로 다른 업무 구성 요소를 하위 구성 요소의 매개 변수로 전송할 수 있다. 이 함수는 하위 구성 요소를 수정하지 않고 조합하는 방식으로 하위 구성 요소를 용기 구성 요소에 포장하는 부작용이 없는 순수한 함수이다.따라서 우리는 이러한 구성 요소의 논리를 바꾸지 않는 상황에서 이 부분의 코드를 결합시켜 코드의 유지보수성을 향상시킬 수 있다.
스스로 손을 써서 고급 구성 요소를 실현하다
전단 항목에서 링크가 있는 빵 부스러기 내비게이션은 매우 자주 사용되지만, 빵 부스러기 내비게이션은 모든 디렉터리 경로와 디렉터리 이름이 비치는 수조를 수동으로 유지해야 하기 때문에, 이곳의 모든 데이터는react-router의 루트표에서 얻을 수 있기 때문에, 우리는 여기서 착안하여 빵 부스러기 내비게이션의 고급 구성 요소를 실현할 수 있다.
먼저 라우팅 테이블이 제공하는 데이터와 대상 빵 부스러기 구성 요소에 필요한 데이터를 살펴보겠습니다.

//   react-router4  route 
let routes = [
 {
  breadcrumb: ' ',
  path: '/a',
  component: require('../a/index.js').default,
  items: [
   {
    breadcrumb: ' ',
    path: '/a/b',
    component: require('../a/b/index.js').default,
    items: [
     {
      breadcrumb: ' 1',
      path: '/a/b/c1',
      component: require('../a/b/c1/index.js').default,
      exact: true,
     },
     {
      breadcrumb: ' 2',
      path: '/a/b/c2',
      component: require('../a/b/c2/index.js').default,
      exact: true,
     },
   }
  ]
 }
]

//  
//   a / b / c1  
const BreadcrumbsComponent = ({ breadcrumbs }) => (
 <div>
  {breadcrumbs.map((breadcrumb, index) => (
   <span key={breadcrumb.props.path}>
    <link to={breadcrumb.props.path}>{breadcrumb}</link>
    {index < breadcrumbs.length - 1 && <i> / </i>}
   </span>
  ))}
 </div>
);

여기서 볼 수 있듯이 빵 부스러기 부품이 제공해야 하는 데이터는 모두 세 가지가 있는데 하나는 현재 페이지의 경로이고 하나는 빵 부스러기가 가지고 있는 문자이며 하나는 이 빵 부스러기의 내비게이션 링크 지향이다.
그 중 첫 번째는react-router에서 제공하는 withRouter 고급 구성 요소 패키지를 통해 하위 구성 요소를 현재 페이지의 위치 속성으로 가져와 페이지 경로를 얻을 수 있습니다.
이후 두 가지는 우리가 루트에 대해 조작을 해야 한다. 우선 루트가 제공한 데이터를 빵 부스러기 내비게이션에 필요한 형식으로 편평하게 하면 우리는 함수를 사용하여 그것을 실현할 수 있다.

/**
 *  react router 
 */
const flattenRoutes = arr =>
 arr.reduce(function(prev, item) {
  prev.push(item);
  return prev.concat(
   Array.isArray(item.items) ? flattenRoutes(item.items) : item
  );
 }, []);
이후 벤드펴기 디렉터리 경로를 현재 페이지 경로와 함께 처리 함수에 비추어 빵 부스러기 내비게이션 구조를 생성합니다.

export const getBreadcrumbs = ({ flattenRoutes, location }) => {
 //  match
 let matches = [];

 location.pathname
  //  , .
  .split('?')[0]
  .split('/')
  //  `getBreadcrumb()` reduce.
  .reduce((prev, curSection) => {
   //  ,  `/x/xx/xxx`  ,pathSection  `/x` `/x/xx` `/x/xx/xxx`  , 
   const pathSection = `${prev}/${curSection}`;
   const breadcrumb = getBreadcrumb({
    flattenRoutes,
    curSection,
    pathSection,
   });

   //  matches 
   matches.push(breadcrumb);

   //  reduce 
   return pathSection;
  });
 return matches;
};

그리고 모든 빵 부스러기 경로 부분에 대해 디렉터리 이름을 생성하고 해당 루트 위치를 가리키는 링크 속성을 첨부합니다.

const getBreadcrumb = ({ flattenRoutes, curSection, pathSection }) => {
 const matchRoute = flattenRoutes.find(ele => {
  const { breadcrumb, path } = ele;
  if (!breadcrumb || !path) {
   throw new Error(
    'Router route  `path`   `breadcrumb`  '
   );
  }
  //  
  // exact   react router4  , 
  return matchPath(pathSection, { path, exact: true });
 });

 //  breadcrumb , 
 if (matchRoute) {
  return render({
   content: matchRoute.breadcrumb || curSection,
   path: matchRoute.path,
  });
 }

 //  routes 
 //  .
 return render({
  content: pathSection === '/' ? ' ' : curSection,
  path: pathSection,
 });
};

이후render 함수로 마지막 빵 부스러기 내비게이션 스타일을 생성합니다.단일 빵 부스러기 구성 요소는render 함수에 이 빵 부스러기가 가리키는 경로path와 이 빵 부스러기 내용이 content 두 개의props를 비추어야 합니다.

/**
 *
 */
const render = ({ content, path }) => {
 const componentProps = { path };
 if (typeof content === 'function') {
  return <content {...componentProps} />;
 }
 return <span {...componentProps}>{content}</span>;
};
이러한 기능 함수가 있으면 패키지 구성 요소를 현재 있는 경로와 루트 속성으로 전송할 수 있는 React 고급 구성 요소를 실현할 수 있습니다.하나의 구성 요소를 전송하고 새로운 같은 구성 요소 구조를 되돌려줍니다. 이렇게 하면 구성 요소 이외의 어떠한 기능과 조작에도 파괴를 주지 않습니다.

const BreadcrumbsHoc = (
 location = window.location,
 routes = []
) => Component => {
 const BreadComponent = (
  <Component
   breadcrumbs={getBreadcrumbs({
    flattenRoutes: flattenRoutes(routes),
    location,
   })}
  />
 );
 return BreadComponent;
};
export default BreadcrumbsHoc;
이 고급 구성 요소를 호출하는 방법도 매우 간단합니다. 현재 있는 경로와 전체reactrouter가 생성한routes 속성만 전송하면 됩니다.
현재 경로를 얻는 방법에 대해, 우리는reactrouter가 제공하는 withRouter 함수를 사용할 수 있으며, 어떻게 사용하는지 관련 문서를 직접 보십시오.
특히 withRouter 자체는 고급 구성 요소로 패키지 구성 요소에location 속성을 포함한 몇 가지 루트 속성을 제공할 수 있다.그래서 이 API도 고급 구성 요소를 배우는 데 좋은 참고가 될 수 있다.

withRouter(({ location }) =>
 BreadcrumbsHoc(location, routes)(BreadcrumbsComponent)
);
Q&A
만약reactrouter가 생성한routes가 자신이 수동으로 유지하는 것이 아니라 로컬이 존재하지 않고 요청을 통해 가져온 것이라면redux에 저장됩니다.react-redux가 제공하는connect 고급 함수로 감싸면 루트가 변할 때 이 빵 부스러기 구성 요소가 업데이트되지 않습니다.사용 방법은 다음과 같습니다.

function mapStateToProps(state) {
 return {
  routes: state.routes,
 };
}

connect(mapStateToProps)(
 withRouter(({ location }) =>
  BreadcrumbsHoc(location, routes)(BreadcrumbsComponent)
 )
);

이것은 사실connect 함수의 버그입니다.react-redux의connect 고급 구성 요소는 전송된 매개 변수 구성 요소에 shouldComponentUpdate라는 갈고리 함수를 실현하기 때문에prop이 변화할 때만 업데이트와 관련된 생명주기 함수 (render 포함) 를 촉발합니다. 분명히, 우리의location 대상은 prop이 매개 변수 구성 요소로 전송되지 않았습니다.
공식 추천 방법은 with Router를 사용하여connect의return value, 즉

withRouter(
 connect(mapStateToProps)(({ location, routes }) =>
  BreadcrumbsHoc(location, routes)(BreadcrumbsComponent)
 )
);
사실 우리는 여기서도 알 수 있듯이 고급 구성 요소는 고급 함수와 같이 구성 요소의 유형에 어떠한 변경도 하지 않기 때문에 고급 구성 요소는 체인식 호출과 같이 임의의 다중 패키지로 구성 요소에 서로 다른 속성을 전달할 수 있고 정상적인 상황에서도 임의로 위치를 바꿀 수 있어 사용에 매우 유연하다.이런 플러그 가능한 특성 때문에 고급 구성 요소는 React 생태의 사랑을 많이 받는다. 많은 개원 라이브러리에서 이런 특성의 그림자를 볼 수 있고 틈이 나면 모두 꺼내 분석할 수 있다.
이 글은 React 고급 구성 요소를 이용하여 빵 부스러기 내비게이션을 실현하는 예시를 소개합니다. 더 많은 React 빵 부스러기 내비게이션 내용은 저희 이전의 글을 검색하거나 아래의 관련 글을 계속 훑어보십시오. 앞으로 많은 응원 부탁드립니다!

좋은 웹페이지 즐겨찾기