[javascript] 클라이언트 라우팅 (react-router 사용) 및 서버 측 라우팅

나는 생각하고 클라이언트와 서버 사이의 라우팅과 혼동됩니다. 요청을 웹 브라우저로 다시 보내기 전에 ReactJS를 서버 측 렌더링에 사용하고 react-router를 클라이언트 측 라우팅으로 사용하여 SPA로 새로 고치지 않고 페이지 사이를 전환한다고 가정합니다.

떠오르는 것은 :

  • 경로는 어떻게 해석됩니까? 예를 들어 홈페이지 ( /home)에서 게시물 페이지 ( /posts) 로의 요청
  • 라우팅은 서버 측 또는 클라이언트에서 어디로 이동합니까?
  • 어떻게 처리되는지 어떻게 압니까?


답변

이 답변은 React Router 버전 0.13.x를 다룹니다. 다가오는 버전 1.0 은 구현 세부 사항이 크게 다를 것으로 보입니다.

섬기는 사람

이것은 server.jsreact-router를 사용한 최소한의 것 입니다.

var express = require('express')
var React = require('react')
var Router = require('react-router')

var routes = require('./routes')

var app = express()

// ...express config...

app.use(function(req, res, next) {
  var router = Router.create({location: req.url, routes: routes})
  router.run(function(Handler, state) {
    var html = React.renderToString(<Handler/>)
    return res.render('react_page', {html: html})
  })
})

어디 routes모듈은 경로의 목록을 보냅니다

var React = require('react')
var {DefaultRoute, NotFoundRoute, Route} = require('react-router')

module.exports = [
  <Route path="/" handler={require('./components/App')}>
    {/* ... */}
  </Route>
]

서버에 요청이있을 때마다 Router수신 URL을 고정 위치로 사용하여 구성된 일회용 인스턴스 를 생성합니다.이 인스턴스는 경로 트리에 대해 확인되어 적절한 일치 경로를 설정하고 최상위 수준으로 다시 호출됩니다. 렌더링 할 경로 처리기와 각 수준에서 일치하는 자식 경로에 대한 레코드. 이것은 <RouteHandler>일치 된 하위 경로를 렌더링하기 위해 경로 처리 구성 요소 내 에서 구성 요소 를 사용할 때 참조되는 내용 입니다.

사용자가 JavaScript를 끄거나로드 속도가 느리면 클릭하는 모든 링크가 서버에 다시 연결되며 위와 같이 다시 해결됩니다.

고객

이것은 client.jsreact-router (동일한 경로 모듈 재사용)를 사용 하는 최소한의 것 입니다.

var React = require('react')
var Router = require('react-router')

var routes = require('./routes')

Router.run(routes, Router.HistoryLocation, function(Handler, state) {
  React.render(<Handler/>, document.body)
})

를 호출 Router.run()하면 백그라운드에서 라우터 인스턴스가 생성됩니다.이 인스턴스는 앱을 탐색 할 때마다 재사용됩니다. URL은 클라이언트에서 동적 일 수 있습니다. 고정 URL.

이 경우 에는 뒤로 / 앞으로 버튼을 눌렀을 때 올바른 일이 발생하는지 확인하기 위해 APIHistoryLocation사용 History하는를 사용하고 있습니다. 또한 HashLocationURL hash을 변경하여 기록 항목을 만들고 window.onhashchange이벤트를 수신하여 탐색을 트리거하는 것도 있습니다.

react-router의 <Link>구성 요소 를 사용할 때 to경로의 이름 인 prop paramsquery경로에 필요한 데이터를 제공합니다. <a>이 구성 요소에 의해 렌더링은이 onClick궁극적으로 호출 핸들러 router.transitionTo()이처럼 보이는 링크를 준 소품 라우터 인스턴스를 :

  /**
   * Transitions to the URL specified in the arguments by pushing
   * a new URL onto the history stack.
   */
  transitionTo: function (to, params, query) {
    var path = this.makePath(to, params, query);

    if (pendingTransition) {
      // Replace so pending location does not stay in history.
      location.replace(path);
    } else {
      location.push(path);
    }
  },

일반 링크의 경우 이는 궁극적으로 location.push()사용중인 위치 유형을 호출 합니다.이 기능은 내역 설정의 세부 정보를 처리하므로 뒤로 및 앞으로 버튼으로 탐색이 작동 router.handleLocationChange()할 것입니다. 새 URL 경로.

그런 다음 라우터 router.dispatch()는 구성된 경로 중 URL과 일치하는 경로를 확인하는 세부 정보를 처리하는 새 URL로 자체 메서드를 호출 한 다음 일치하는 경로에 대해 존재하는 모든 전환 후크 를 호출합니다 . 라우트 핸들러에서 이러한 전환 후크를 구현하여 경로가 멀어 지거나 이동하려고 할 때 작업을 수행 할 수 있으며, 원하는대로 전환을 중단 할 수 있습니다.

전환이 중단되지 않은 경우 마지막 단계는 Router.run()URL의 모든 세부 정보와 일치하는 경로가있는 상태 개체와 최상위 수준 핸들러 구성 요소 를 사용하여 제공 한 콜백을 호출하는 것 입니다. 최상위 수준 처리기 구성 요소는 실제로 Router일치 된 최상위 경로 처리기를 렌더링하는 인스턴스 자체입니다.

위의 프로세스는 클라이언트에서 새 URL로 이동할 때마다 다시 실행됩니다.

예제 프로젝트


답변

1.0에서 React-Router 는 peerDependency로 history 모듈 에 의존합니다 . 이 모듈은 브라우저에서 라우팅을 다룹니다. 기본적으로 React-Router는 HTML5 History API ( pushState, replaceState)를 사용하지만 해시 기반 라우팅을 사용하도록 구성 할 수 있습니다 (아래 참조).

경로 처리는 이제이면에서 수행되며 ReactRouter는 경로가 변경 될 때 새로운 props를 Route 핸들러로 보냅니다. 라우터에는 onUpdate경로가 변경 될 때마다 새로운 prop 콜백이 있으며 <title>, 예를 들어 페이지 뷰 추적 또는 .

클라이언트 (HTML5 라우팅)

import {Router} from 'react-router'
import routes from './routes'

var el = document.getElementById('root')

function track(){
  // ...
}

// routes can be children
render(<Router onUpdate={track}>{routes}</Router>, el)

클라이언트 (해시 기반 라우팅)

import {Router} from 'react-router'
import {createHashHistory} from 'history'
import routes from './routes'

var el = document.getElementById('root')

var history = createHashHistory()

// or routes can be a prop
render(<Router routes={routes} history={history}></Router>, el)

섬기는 사람

서버에서 사용할 수 있습니다 ReactRouter.match. 이것은 서버 렌더링 가이드 에서 가져온 것입니다.

import { renderToString } from 'react-dom/server'
import { match, RoutingContext } from 'react-router'
import routes from './routes'

app.get('*', function(req, res) {
  // Note that req.url here should be the full URL path from
  // the original request, including the query string.
  match({ routes, location: req.url }, (error, redirectLocation, renderProps) => {
    if (error) {
      res.status(500).send(error.message)
    } else if (redirectLocation) {
      res.redirect(302, redirectLocation.pathname + redirectLocation.search)
    } else if (renderProps) {
      res.status(200).send(renderToString(<RoutingContext {...renderProps} />))
    } else {
      res.status(404).send('Not found')
    }
  })
})


답변