React現在のページに制限されているアプリケーション、/some/static/page
。のアプリケーションは<base href="/">
in <head>
はすべてのページにあり、それに依存しています。これは変更できません。
React 16、Reactルーター4および<HashRouter>
:
export class App extends React.Component {
render() {
return (
<HashRouter>
<div>
<Route exact path="/" component={Root} />
</div>
</HashRouter>
);
}
}
すべてのルートはテスト目的で無効にすることができますが、これにより動作が変わることはありません。
これはcreate-react-app
プロジェクトです 問題を示しています。複製する手順は次のとおりです。
npm i
npm start
http://localhost:3000/some/static/page
に移動しますHashRouterは、明らかに<base>
の影響を受けます。初期化時に/some/static/page
から/#/
にリダイレクトしますが、/some/static/page#/
または/some/static/page/#/
(IE 11)。
/#/
にリダイレクトされる前に、Root
コンポーネントがすぐにスプラッシュします。
/foo/#/
の場合は<base href="/foo">
にリダイレクトし、/some/static/page/#/
タグが削除されると<base>
にリダイレクトします。
この問題は、ChromeおよびFirefox(最新バージョン)に影響しますが、Internet Explorer(IE 11)には影響しません。)
<HashRouter>
が<base>
の影響を受けるのはなぜですか?ここで使用されているのは、ロケーションパスに影響を与えるものではなく、ハッシュのみであるためです。
これはどのように修正できますか?
実際これはhistory
から。 コード が表示される場合、createHashHistory
のみを使用し、children
を設定します。したがって、これと同等です:
import React from 'react';
import { Route, Router } from 'react-router-dom';
import { createHashHistory } from 'history';
const Root = () => <div>Root route</div>;
export default class App extends React.Component {
history = createHashHistory({
basename: "", // The base URL of the app (see below)
hashType: "slash", // The hash type to use (see below)
// A function to use to confirm navigation with the user (see below)
getUserConfirmation: (message, callback) => callback(window.confirm(message)),
});
render() {
return (
<Router history={this.history}>
<div>Router
<Route exact path="/" component={Root} />
</div>
</Router>
);
}
}
同じ問題が表示されます。次に、history
コードを次のように変更した場合:
import {createBrowserHistory } from 'history';
...
history = createBrowserHistory({
basename: "", // The base URL of the app (see below)
forceRefresh: false, // Set true to force full page refreshes
keyLength: 6, // The length of location.key
// A function to use to confirm navigation with the user (see below)
getUserConfirmation: (message, callback) => callback(window.confirm(message))
});
問題はなくなりますが、hash
は絶対に使用しないでください。したがって、問題はHashRouter
からではなく、history
からです。
これはhistory
から来るので、これを見てみましょう thread 。そのスレッドを読んだ後、これはhistory
からfeatureであると結論付けることができます。
したがって、<base href="/">
を設定すると、hash
(#)を使用しているため、ブラウザがロードされたとき(実際はcomponentDidMount
の後に)hash
(#)が追加されますあなたの場合some/static/page
=> some/static/page
+ /
=> /
+ #/
=> /#/
。 componentDidMount
set debugger
をチェックインして、ルートを追加する前にキャッチできます。
単に、要素<base href>
を削除するか、HashRouter
を使用しないでください。
特定のcomponent
から回避する必要があるが、避けたい場合は、これをclass
の前に置いてください
const base = document.querySelector("base");
base.setAttribute('href', '');
リンクを保持し、base
ルーターを使用するためにhash
タグを保持したいので、ここで私が思うに近い解決策です。
1。タグbase
を空に設定します。
const base = document.querySelector('base');
base.setAttribute('href', '');
そのコードをApp
コンポーネント(ルートラップコンポーネント)に入れて1回呼び出します。
2。 componentDidMount
が設定し直した場合
componentDidMount() {
setTimeout(() => {
base.setAttribute('href', '/');
}, 1000);
}
タイムアウトを使用して、反応したレンダリング仮想domを待ちます.
これは非常に近いと思います(テストしてみてください)。 hash
ルーターを使用しているため、インデックスhtmlからのリンクは安全です(reactでオーバーライドするのではなく、base
タグで保持します)。また、cssリンク<link rel="stylesheet" href="styles.css">
でも機能します。
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base#Hint が表示される場合、#target URLであっても<base>
を使用している予想される動作です。
そして https://reacttraining.com/react-router/web/api/HashRouter basename:string section:適切にフォーマットされたbasenameにはスラッシュが必要ですが、スラッシュなし。
したがって、HashRouter
要素に別のベース名を定義するか、<base>
から末尾のスラッシュを削除する必要があります。
history
パッケージの問題です。解決済みです。 this pr をご覧ください
一時的な修正として、package.json
でこのブランチを指定することをお勧めします
"dependencies": {
...
"history": "git://github.com/amuzalevskiy/history.git",
...
}
そして、修正が元のブランチにマージされると、これを修正されたメインのnpmモジュールに戻します
リポジトリに関して:publish
スクリプトを実行せずに元のリポジトリを使用することは不可能なので、 microbouji solution でnpm run build
を実行し、結果をコミットしました
this answer で説明されている修正を適用するHOCで終了しました:
function withBaseFix(HashRouter) {
return class extends React.Component {
constructor() {
super();
this.baseElement = document.querySelector('base');
if (this.baseElement) {
this.baseHref = this.baseElement.getAttribute('href');
this.baseElement.setAttribute('href', '');
}
}
render() {
return <HashRouter {...this.props}>{this.props.children}</HashRouter>;
}
componentDidMount() {
if (this.baseElement)
this.baseElement.setAttribute('href', this.baseHref);
}
}
};
const FixedHashRouter = withBaseFix(HashRouter);
...
<FixedHashRouter>
<div>
<Route exact path="/" component={Root} />
</div>
</FixedHashRouter>
...
HashRouter
および<base>
タグに関する観察は正しいです。ブラウザーの違いに関する問題をここに提出しました: https://github.com/ReactTraining/history/issues/574 および対応するPRをここに修正します: https:// github。 com/ReactTraining/history/pull/577
当面、必要なすべてのルーティングについてはわかりませんが、reactアプリが/some/static/page/
の下に完全に存在する場合、おそらく次のように動作させることができます。
<BrowserRouter basename="/some/static/page">
。