react-router를 사용하여 브라우저에서 / # /을 중지하는 방법은 무엇입니까?


103

/#/react-router를 사용할 때 브라우저의 주소 표시 줄에 표시 되지 않도록 하는 방법이 있습니까? 그것은 ReactJS입니다. 즉, 링크를 클릭하여 새 경로로 이동하면 localhost:3000/#/또는 localhost:3000/#/about. 경로에 따라 다릅니다.


1
HashHistoryiso 사용 때문 BrowserHistory입니다. 이 주제에 대한 많은 배경 정보를 제공하는 이 SO 질문을 참조하십시오 .
Stijn de Witt

답변:


78

react-router 버전 1, 2 및 3의 경우 URL 매핑 체계에 대한 경로를 설정하는 올바른 방법은 기록 구현을의 history매개 변수 에 전달하는 것 입니다 <Router>. 로부터 역사 문서 :

간단히 말해서 히스토리는 브라우저의 주소 표시 줄에서 변경 사항을 수신하는 방법을 알고 라우터가 경로를 일치시키고 올바른 구성 요소 집합을 렌더링하는 데 사용할 수있는 위치 개체로 URL을 구문 분석합니다.

버전 2 및 3

react-router 2와 3에서 경로 구성 코드는 다음과 같습니다.

import { browserHistory } from 'react-router'
ReactDOM.render (( 
 <Router history={browserHistory} >
   ...
 </Router> 
), document.body);

버전 1

버전 1.x에서는 대신 다음을 사용합니다.

import createBrowserHistory from 'history/lib/createBrowserHistory'
ReactDOM.render (( 
  <Router history={createBrowserHistory()} >
   ...
  </Router> 
), document.body);

출처 : 버전 2.0 업그레이드 가이드

버전 4

다가오는 react-router 버전 4의 경우 구문이 크게 변경 BrowserRouter되었으며 라우터 루트 태그 로 사용하는 것이 필요합니다 .

import BrowserRouter from 'react-router/BrowserRouter'
ReactDOM.render (( 
  <BrowserRouter>
   ...
 <BrowserRouter> 
), document.body);

Source React Router 버전 4 문서


6
참고 historyA는 독립 실행 형 패키지 를 설치해야합니다.
Jan Klimo 2015 년

4
그들은 변경 browserHistory버전 2.x에서 : import { browserHistory } from 'react-router' <Router history={browserHistory} />체크인 반응 라우터 업그레이드 가이드
pistou

@pistou 감사합니다. 버전 2.0에 대한 답변을 업데이트했습니다!
Adam Brown

1
의 경우 hashHistory끝에이 쿼리 매개 변수를 제거하는 방법이 있습니까? http://localhost:8080/#/dashboard?_k=yqwtyu
콘 Antonakos

2
@Matt 작동하지만 서버에 대한 지원이 필요합니다. 새로 고칠 때 경로가있는 URL로 서버에 도달하기 때문입니다.
Stijn de Witt

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

현재 버전 0.11 앞으로를 들어, 당신은 추가 할 필요 Router.HistoryLocationRouter.run(). <Routes>이제 더 이상 사용되지 않습니다. 0.12.x HistoryLocation 구현에 대한 업그레이드 가이드참조하십시오 .


1
이것은 내 앱을 완전히 망쳤습니다. 현재 구현이 버그가있는 것 같습니까?
ninjaneer

2
@Ninja는 아마도 react 및 react-router에 대한 정확한 버전 번호, 실패한 코드 및 수신 된 오류와 함께 새 질문을 게시 할 수 있습니다.
pxwise

@Chet 반응 라우터 문서가 섞인 것 같습니다. 업그레이드 가이드에있는 HistoryLocation에 대한 유일한 참조 링크가 업데이트되었습니다.
pxwise 2015 년

21

IE8을 지원할 필요가없는 경우 브라우저 기록을 사용할 수 있으며 react-router가 window.pushState해시를 설정하는 대신 사용 합니다.

이를 정확히 수행하는 방법은 사용중인 React Router의 버전에 따라 다릅니다.


@ ben-alpert에게 감사합니다. 지금 가져옵니다.
Giant Elk

1
나는 <Routes location="history">경로에있을 때 브라우저를 새로 고칠 때까지 모두 정상적으로 작동한다고 추가 했습니다. 즉 localhost:3000/about404 오류가 발생합니다. 그게 예상되는 python -m SimpleHTTPServer 3000건가요?
Giant Elk

5
서버 측에서 푸시 상태 URL을 처리 할 수 ​​있는지 확인해야합니다. 이 경우 앱을 제공하는 것이 무엇이든 항상 동일한 루트에 도착하는 모든 URL을 전송하는지 확인해야 함을 의미합니다. 그래서 /about실제로 루트 페이지를로드합니다 /. 그렇지 않으면 서버가 일치하는 경로를 /about찾고 아무것도 찾지 못합니다 (404). 나는 개인적으로 파이썬을 사용하지 않지만 일반적으로 수동 경로 /*또는 /.*-> /작동 중 하나를 찾거나 html5Mode서버 설정에서 URL 이라고 할 수 있습니다 .
Mike Driver

3
IE9는 pushState도 지원하지 않습니다. "IE9를 지원할 필요가 없다면"맞습니까? 내가 틀 렸으면 좋겠어.
Cymen

1
그 github 링크는 현재 찾을 수없는 페이지입니다.
k00k

9

실제로 .htaccess를 사용하여이를 수행 할 수 있습니다. 브라우저에는 일반적으로 쿼리 문자열 구분 기호가 필요 ?하거나 #쿼리 문자열이 시작되고 디렉터리 경로가 끝나는 위치를 결정 해야합니다 . 우리가 원하는 최종 결과는 www.mysite.com/dir 웹 서버가 요청한 디렉토리를 검색하기 전에 문제를 파악해야합니다 /dir. 따라서 .htaccess프로젝트의 루트에 파일을 배치합니다 .

    # Setting up apache options
    AddDefaultCharset utf-8
    Options +FollowSymlinks -MultiViews -Indexes
    RewriteEngine on

    # Setting up apache options (Godaddy specific)
    #DirectoryIndex index.php
    #RewriteBase /


    # Defining the rewrite rules
    RewriteCond %{SCRIPT_FILENAME} !-d
    RewriteCond %{SCRIPT_FILENAME} !-f

    RewriteRule ^.*$ ./index.html

그런 다음 window.location.pathname을 사용하여 쿼리 매개 변수를 얻습니다.

그런 다음 원하는 경우 반응 경로를 사용하지 않고 원하는 경우 URL 및 브라우저 기록을 조작 할 수 있습니다. 이것이 누군가에게 도움이되기를 바랍니다 ...


Jboss에 해당하는 것은 무엇입니까?
Raghavan

5

히스토리 패키지 설치

npm install history --save

다음으로 히스토리에서 createHistory 및 useBasename 가져 오기

import { createHistory, useBasename } from 'history';
...
const history = useBasename(createHistory)({
  basename: '/root' 
});

앱 URL이 www.example.com/myApp이면 / root는 / myApp이어야합니다.

히스토리 변수를 라우터에 전달

render((
  <Router history={history}>
    ...
  </Router>
), document.getElementById('example'));

이제 모든 링크 태그에 대해 모든 경로 앞에 "/"를 추가합니다.

<Link to="/somewhere">somewhere</Link>

솔루션의 영감은 React-Router 예제 에서 나왔는데 , 불행히도 API에 제대로 문서화되지 않았습니다.


노드 서버가 필요합니까? 동일한 URL 스타일을 얻으려고 노력하고 있지만 클라이언트 측을 통해서만 가능합니다. 가능할까요?
Sebastialonso

1
아니요, 노드 서버가 필요하지 않습니다. 사실 저는 django 백엔드에서 실행 중입니다. 그러나 도구에 대한 노드가 필요할 수 있습니다.
Mox

1
좋아, 나는이 접근 방식을 시도했습니다. F5 키를 누르면 "찾을 수 없음"이 표시됩니다. 이 역사가 그것을 다룰 수 있습니까?
Sebastialonso

u를 찾을 수 없으면 서버에서 반환합니다. 이는 URL 패턴이 반응 라우터의 일부가 아님을 의미합니다.
Mox

1
예, 조금 더 읽어 보니 모든 것이 명확 해졌습니다. 키없이 hashHistory로 끝냈습니다.
Sebastialonso

3

해시 후 표시 할 내용을 처리하는 또 다른 방법은 (따라서 pushState를 사용하지 않는 경우!) CustomLocation을 생성하고 ReactRouter 생성시로드하는 것입니다.

예를 들어, 크롤링을위한 Google 사양을 준수하기 위해 해시 뱅 URL (#!)을 사용하려면 다음과 같은 원본 HashLocation을 주로 복사하는 HashbangLocation.js 파일을 만들 수 있습니다.

'use strict';

var LocationActions = require('../../node_modules/react-router/lib/actions/LocationActions');
var History = require('../../node_modules/react-router/lib/History');

var _listeners = [];
var _isListening = false;
var _actionType;

function notifyChange(type) {
  if (type === LocationActions.PUSH) History.length += 1;

  var change = {
    path: HashbangLocation.getCurrentPath(),
    type: type
  };

  _listeners.forEach(function (listener) {
    listener.call(HashbangLocation, change);
  });
}

function slashToHashbang(path) {
  return "!" + path.replace(/^\//, '');
}

function ensureSlash() {

  var path = HashbangLocation.getCurrentPath();
  if (path.charAt(0) === '/') {
    return true;
  }HashbangLocation.replace('/' + path);

  return false;
}

function onHashChange() {
  if (ensureSlash()) {
    // If we don't have an _actionType then all we know is the hash
    // changed. It was probably caused by the user clicking the Back
    // button, but may have also been the Forward button or manual
    // manipulation. So just guess 'pop'.
    var curActionType = _actionType;
    _actionType = null;
    notifyChange(curActionType || LocationActions.POP);
  }
}

/**
 * A Location that uses `window.location.hash`.
 */
var HashbangLocation = {

  addChangeListener: function addChangeListener(listener) {
    _listeners.push(listener);

    // Do this BEFORE listening for hashchange.
    ensureSlash();

    if (!_isListening) {
      if (window.addEventListener) {
        window.addEventListener('hashchange', onHashChange, false);
      } else {
        window.attachEvent('onhashchange', onHashChange);
      }

      _isListening = true;
    }
  },

  removeChangeListener: function removeChangeListener(listener) {
    _listeners = _listeners.filter(function (l) {
      return l !== listener;
    });

    if (_listeners.length === 0) {
      if (window.removeEventListener) {
        window.removeEventListener('hashchange', onHashChange, false);
      } else {
        window.removeEvent('onhashchange', onHashChange);
      }

      _isListening = false;
    }
  },

  push: function push(path) {
    _actionType = LocationActions.PUSH;
    window.location.hash = slashToHashbang(path);
  },

  replace: function replace(path) {
    _actionType = LocationActions.REPLACE;
    window.location.replace(window.location.pathname + window.location.search + '#' + slashToHashbang(path));
  },

  pop: function pop() {
    _actionType = LocationActions.POP;
    History.back();
  },

  getCurrentPath: function getCurrentPath() {
    return decodeURI(
    // We can't use window.location.hash here because it's not
    // consistent across browsers - Firefox will pre-decode it!
    "/" + (window.location.href.split('#!')[1] || ''));
  },

  toString: function toString() {
    return '<HashbangLocation>';
  }

};

module.exports = HashbangLocation;

slashToHashbang 함수에 유의하십시오 .

그럼 넌해야 해

ReactRouter.create({location: HashbangLocation})

그리고 그게 다야 :-)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.