분류 Reactjs

React 지연 : 미리로드 보기 사용

컨텐츠 정보

  • 조회 313 (작성일 )

본문

경로 기반 코드 분할 앱에 사전 로드를 추가하는 방법 


React Loadable과 React Lazy 및 Suspense를 처음 사용한 이후로, 나는 큰 응용 프로그램을 위한 라우트 기본 코드 분할을 크게 옹호했습니다. 이를 통해 클라이언트는 화면에 무언가를 렌더링 하기 전에 전체 앱을 다운로드하지 않고 실제로 액세스하는 앱의 청크만 로드 할 수 있습니다. 이 패턴은 React Library의 공식 문서에도 나와 있습니다.


그러나 나는 항상 최종 사용자 경험을 더 좋게 만드는 방법에 대한 팁과 요령을 찾고 있습니다. 그래서 최근에 경로 기본 코드 분할에서 청크를 미리 로드하는 방법의 문제를 해결하려고 시도했습니다. 청크 간 탐색을 보다 원활하게 합니다. 일부 Gatsby 사이트에서 이 동작을 보았고 그것이 얼마나 이산적이고 효율적인지 정말 좋아했습니다. 그렇기 때문에 사전 로드 구현에 대한 독자적인 의견을 작성하고 모든 사람과 공유하기로 결정했습니다.


참고 :이 구현은 react-router-dom을 기반으로 하고 16.8.0 이상을 반응 시킵니다. 이 게시물에 사용 된 코드는 여기에 있습니다.


https://blog.maximeheckel.com/posts/preloading-views-with-react 


Our app 


방문 페이지 경로, 할 일 목록을 가져 오는 또 다른 일, 할 일을 검사하는 다른 일 등 여러 경로가 있는 React 앱을 살펴 보겠습니다. 각 경로는 특정 뷰 / 구성 요소를 렌더링 합니다. 코드 분할에 대한 React 문서를 주의 깊게 읽고 React.Lazy 및 React.Suspense를 사용하여 다음과 유사한 코드베이스를 얻었습니다.


import React from 'React';

import { Route, Router, Switch } from 'react-router-dom'


const App = React.lazy(() => import('./App'));

const Todos = React.lazy(() => import('./Todos'));

const Todo = React.lazy(() => import('./Todo'));


const routes = [

  { path: "/", exact: true, component: App },

  { path: "/todos", exact: true, component: Todos },

  { path: "/todos/:id", exact: true, component: Todo }

];


ReactDOM.render(

    <Router>

        <React.Suspense fallback={"Loading"}>

            <Switch>

                {routes.map(route => (

                    <Route

                      key={route.path}

                      exact={route.exact}

                      path={route.path}

                      component={route.component}

                    />

                ))}         

            </Switch>

        </React.Suspense>

    </Router>

);


앱을 실행하면 브라우저의 개발자 도구에서 한보기에서 다른 보기로 이동하는 것이 앱의 다른 "조각"또는 "청크"를 로드하고 있음을 알 수 있습니다. 이제 사용자가 새 경로로 이동 한 후 로드 하지 않고 탐색 링크 중 하나를 가리킬 때 이러한 청크를 로드 할 수 있는 방법에 초점을 맞추겠습니다.


React Lazy를 사용하여 사전로드 컴포넌트 


뷰를 사전 로드 하려면 청크에서 사전로드 메소드를 호출 할 수 있어야 합니다. 이 사전 로드 메소드는 React Lazy에 전달 된 가져 오기 명령문을 실행하기 위해 호출 될 수 있습니다. 이러한 기능은 React Loadable에서 즉시 사용할 수 있지만 React Lazy는 제공하지 않는 것 같으므로 다음 코드를 사용하여 처음부터 구현해야 합니다.


const ReactLazyPreload = importStatement => {

  const Component = React.lazy(importStatement);

  Component.preload = importStatement;

  return Component;

};


이제 코드 분할 청크를 다음과 같이 다시 선언 할 수 있습니다.


const App = ReactLazyPreload(() =>

  import("./App")

);


const Todos = ReactLazyPreload(() =>

  import("./Todos")

);


const Todo = ReactLazyPreload(() =>

  import("./Todo")

);


위의 코드를 사용하여 컴포넌트에 대해 프리로드 메소드를 호출 할 수 있으며, 그 결과 각각의 컴포넌트가 각각의 청크를로드하게됩니다.

App.preload()

Todos.preload()

Todo.preload()


주어진 경로에 대한 올바른 구성 요소에 대한 사전 로드 호출 


사용자가 주어진 링크를 가리킬 때 미리 로드 할 구성 요소를 지정할 수 있지만 경로를 기반으로 미리 로드 할 구성 요소를 "찾을"수 있다면 좋지 않을까요? 이 포스트의 첫 번째 코드 스니펫을 살펴보면 React Router Route 구성 요소에 필요한 모든 속성이 포함 된 routes 객체를 선언했음을 알 수 있습니다. 이것은 의도적이며 어떤 구성 요소가 어떤 경로와 연관되어 있는지 찾는 데 유용합니다.


findComponentForRoute 함수를 선언하자 :


import { matchPath } from "react-router-dom";


const findComponentForRoute = (path, routes) => {

  const matchingRoute = routes.find(route =>

    matchPath(path, {

      path: route.path,

      exact: route.exact

    })

  );


  return matchingRoute ? matchingRoute.component : null;

};


React Router에는 matchPath라는 매우 편리한 메소드가 제공되는데, 주어진 경로에 대해 두 번째 인수로 전달 된 경로가 일치하면 true를 반환합니다. 위의 코드 스니펫의 함수는 이 방법을 사용하며 일치하는 것이 있으면 연결된 구성 요소를 반환하거나 경로를 찾지 못하면 null을 반환합니다. 


주어진 경로에 관련된 컴포넌트를 찾을 수 있는 방법이 있으므로, 미리 로드 하는 함수를 만들 수 있습니다 :


const preloadRouteComponent = (path) => {

  const component = findComponentForRoute(path, routes);


  if (component && component.preload) {

    component.preload();

  }

};


마지막으로 onMouseEnter 이벤트 핸들러에 이 함수를 모든 Link 구성 요소에 추가하고 하루에 호출 할 수 있지만 방금 구현 한 기능을 보다 쉽게 ​​사용할 수 있습니다. Link와 동일한 소품을 가지지 만 preloadRouteComponent 함수를 사용하는 LinkWithPreload 구성 요소를 만들어 보겠습니다.


import { Link } from 'react-router-dom'


...


const LinkWithPreload = ({ to, onPreload, ...rest }) => {

  return (

    <Link

      to={to}

      onMouseEnter={() => preloadRouteComponent(to)}

      {...rest}

    />

  );

};


export default LinkWithPreload;


이제 링크 대신이 구성 요소를 사용하여 아래에서 볼 수 있듯이 앱에서 탐색 링크를 가리키면 해당 링크의 경로와 관련된 청크를 로드해야 합니다.


Gif showcasing the preloading behavior we implemented using React Lazy and Suspense. When hovering, the chunk will load and the transition to the new route is seemless. However, if we don't hover long enough and click on the link, we will see the fallback component from Suspense until the chunk is fully loaded. 



전체 코드를 보시겠습니까? 이 기사에 소개 된 앱을 여기에서 사용할 수 있게 했습니다!