Universal Router를 사용한 React의 라우팅

22843 단어 tutorialreact
React Router의 "쉬운"대안으로 UniversalRouter (1.6kB zip)의 빠른 쇼케이스.



뭐야? 라우터에 사용되는 코드는 React 구성 요소에 포함되지 않습니다. 주어진 경로에서 코드 실행을 허용한 다음 렌더링을 위해 React 구성 요소를 React에 전달하는 것은 순수한 Javascript 코드입니다. 브라우저 탐색 및 History interface 을 사용합니다.

이것을 사용하는 요점은 무엇입니까? 예: 페이지를 탐색할 때 데이터를 렌더링할 수 있습니다. 구성 요소에서 useEffect를 사용하는 대신 데이터를 미리 가져온 다음 상태 비저장 React 구성 요소에 인수로 전달할 수 있습니다. 이 모든 작업은 비동기식으로(이중 렌더링 없음).
마지막으로 코드가 꽤 안정적입니다. :)

이 쇼케이스에서는 리디렉션을 사용하지 않고 각 페이지 상단에 유지되고 구성 요소를 children로 렌더링하는 링크가 있는 "nabvar"구성 요소만 사용합니다.

"링크" 지도



navbar는 링크 모음입니다. 각 링크에는 pathtitle 속성이 있습니다. 다음 속성을 포함하는 객체 맵을 정의합니다.

export const useLinks = [
  { path: "/", title: "Home" },
  { path: "/users", title: "pre-render" },
  { path: "/vusers", title: "Valtio store" },
  [...]
];


이 배열의 각 개체는 "링크"요소의 인수가 됩니다.

const Link = ({ path, title, handler }) => 
  <a href={path} onClick={handler}>
    {title}
  </a>

onClick 처리기는 상위 구성 요소 "Navbar"에서 정의됩니다. 주어진 경로에 대해 추가 코드를 실행해야 하는 경우 아래에서 볼 수 있듯이 경로 배열에서 정의할 수 있습니다.

내브바


<Link /> 개체의 맵을 반복하여 Navbar 구성 요소를 빌드합니다.
"onClick"핸들러는 단순히 찾은 경로 이름 속성을 browser history session 에 푸시합니다. Navbar는 모든 구성 요소를 자식으로 렌더링합니다.

const NavBar = ({ children }) => {
  function handleNav(e) {
    e.preventDefault();
    history.push({ pathname: e.target.pathname });
  }

  return (
    <>
      {useLinks.map(({ path, title }) => (
        <Link key={title} path={path} title={title} handler={handleNav} />
      ))}
      {children}
    </>
  );
};


경로



라우팅은 route 개체의 배열인 path 개체를 정의하여 이루어집니다. 경로 개체는 path , actionchildren 세 개의 예약된 키로 정의됩니다. 경로 개체의 형식은 다음과 같습니다.

{path: "/component", action: handler, children: []}


선택적children 배열은 중첩 경로를 제공합니다.
action는 단순히 함수입니다. 결국 React 구성 요소를 반환합니다(이 경우에는 리디렉션이 없으므로). 모든action은 비동기식으로 만들 수 있으며 특히 동적 가져오기를 만들 수 있습니다.

예를 들어 API에서 검색된 데이터를 표시하는 페이지로 이동한다고 가정합니다. 조치는 다음과 같습니다.

async function PreFetch() {
  const users = await fetchComments(8);
  const { default: Users } = await import("../utils/users");
  return <Users data={users} />;
}


우리의 경로 객체는 다음과 같습니다.

{ path: "/users", action: async () => PreFetch() }


경로 개체에서 사용할 수 있는 개체context를 허용합니다. action는 경로에서 context 객체를 속성으로 받아들입니다. 예를 들어 데이터 저장소를 전달하는 데 사용할 수 있으므로 코드를 통해 저장소를 확산할 필요가 없습니다. 경로를 통해 구성 요소에 주입하기만 하면 됩니다. 쉬운!
컨텍스트 개체는 필요한 경우 "매개 변수"도 캡처합니다.

UniversalRouter가 횡단할 경로 배열의 예:

const routes = [
  {
    // wrapping the routes with the Navbar and render every component as a child
    path: "",
    action: async ({ next }) => {
      const component = await next();
      const { default: NavBar} = await import('./NavBar')
      return component && <NavBar>{component}</NavBar>
    },
    children: [
      {
        path: "/",
        action: async () =>
          import(".Home").then(({ Home }) => <Home />)
      },
      {
        path: "/users",
        action: async () => PreFetch()
      },
      {
        path: "/vusers",
        async action({ vStore }) {
          await vStore.getUsers(2);
          const { default: Users } = await import("../utils/users");
          return <Users data={vStore.users} />;
        }
      },

      {
        path: "(.*)",
        action: () => <img scr="404.webp" ...</h1>
      }
    ]
  }
];



const Users = ({ data }) => (
    <>{data && data.map((user) => <User key={..}... />)}</>
  );


발티오 경로 구문 분석 및 렌더링


  • 다음과 같이 을 시작합니다.

  • import { createBrowserHistory } from "history";
    export default createBrowserHistory();
    


  • router 개체를 시작하고 context가 필요할 때마다 일부 action를 전달할 수 있습니다. 예를 들어 Valtio에서 관리하는 데이터 저장소(여기서는 vStore라고 함)를 사용합니다.

  • // example of Valtio store
    import { proxy, useSnapshot } from "valtio";
    import { fetchUsers } from "./fetchUsers";
    export { useSnapshot };
    
    export const vStore = proxy({
      users: null,
      async getUsers(id) {
        vStore.users = await fetchUsers(id);
      },
    });
    


    생성자의 context 키에 전달할 수 있으며 모든 경로 개체action 메서드는 필요할 때마다 이 저장소를 action(context) {...}와 함께 사용할 수 있습니다.

    const router = new UniversalRouter(routes, {context: {vStore}});
    


    브라우저 기록 세션 마지막으로, 이것은 어떻게 작동합니까?


    history는 경로 변경을 수신하고 renderRoute 기능을 트리거합니다. UniversalRouter는 경로와 일치하는 항목을 찾기 위해 생성자에서 사용되는 "routes"배열을 가로지릅니다. 그런 다음 React 구성 요소를 반환하는 작업을 실행합니다(이 경우). 그런 다음 반환된 함수에서 React.render 함수를 호출합니다.

    import { createRoot } from "react-dom/client";
    import React from "react";
    
    import UniversalRouter from "universal-router";
    import history from "./router/history";
    
    import routes from "./router/routes";
    
    import { vStore } from "./valtio/vStore";
    
    
    const context = { vStore };
    
    const router = new UniversalRouter(routes, { context });
    
    const root = createRoot(document.getElementById("root"));
    
    async function renderRoute(location) {
      try {
        // "history" returns a path, and "router" finds a match in the routes array
        const page = await router.resolve({
          pathname: location.pathname
        });
    
        return root.render(<>{page}</>);
      } catch (err) {
        console.log(err);
        return root.render(<p>Wrong!</p>);
      }
    }
    
    history.push("/");
    
    history.listen(({ location }) => renderRoute(location));
    renderRoute(history.location);
    

    좋은 웹페이지 즐겨찾기