私は2つを持っています <Route>
sはreact-routerで作成されました。
ユーザーが[リストに戻る]をクリックすると、ユーザーがリストのどこにいたかスクロールします。
これどうやってするの?
codesandboxでの作業例
React Router v4は、すぐにスクロール復元をサポートしません。現在のところ、どちらもサポートしていません。セクションの React Router V4-Scroll Restoration のドキュメントで、詳細を読むことができます。
したがって、これをサポートするロジックを作成するのはすべての開発者次第ですが、この機能を実現するためのツールはいくつかあります。
.scrollIntoView()
は要素に対して呼び出すことができ、ご想像のとおり、スクロールして表示します。サポートは非常に良好で、現在、ブラウザの97%がサポートしています。 ソース:icanuse
<Link />
_コンポーネントは状態を渡すことができますReact RouterのLinkコンポーネントには、文字列の代わりにオブジェクトを提供できるto
プロパティがあります。これがだれだ。
_<Link to={{ pathname: '/card', state: 9 }}>Card nine</Link>
_
状態を使用して、レンダリングされるコンポーネントに情報を渡すことができます。この例では、状態に番号が割り当てられます。これは質問に答えるのに十分です。後で表示しますが、それは何でもかまいません。 _/card
_をレンダリングするルート_<Card />
_は、props.location.stateで変数stateにアクセスできるようになり、使用できます希望通り。
さまざまなカードをレンダリングするときに、それぞれに一意のクラスを追加します。これにより、渡すことができる識別子が得られ、カードリストの概要に戻るときにこのアイテムをスクロールして表示する必要があることがわかります。
<Cards />
_はリストをレンダリングします。各アイテムは一意のクラスを持ちます。Link />
_は一意の識別子を_<Card />
_に渡します。<Card />
_は、カードの詳細と一意の識別子を持つ戻るボタンをレンダリングします。<Cards />
_がマウントされると、.scrollIntoView()
は、_props.location.state
_のデータを使用して以前にクリックされたアイテムにスクロールします。以下は、さまざまな部分のコードスニペットです。
_// Cards component displaying the list of available cards.
// Link's to prop is passed an object where state is set to the unique id.
class Cards extends React.Component {
componentDidMount() {
const item = document.querySelector(
".restore-" + this.props.location.state
);
if (item) {
item.scrollIntoView();
}
}
render() {
const cardKeys = Object.keys(cardData);
return (
<ul className="scroll-list">
{cardKeys.map(id => {
return (
<Link
to={{ pathname: `/cards/${id}`, state: id }}
className={`card-wrapper restore-${id}`}
>
{cardData[id].name}
</Link>
);
})}
</ul>
);
}
}
// Card compoment. Link compoment passes state back to cards compoment
const Card = props => {
const { id } = props.match.params;
return (
<div className="card-details">
<h2>{cardData[id].name}</h2>
<img alt={cardData[id].name} src={cardData[id].image} />
<p>
{cardData[id].description} <a href={cardData[id].url}>More...</a>
</p>
<Link
to={{
pathname: "/cards",
state: props.location.state
}}
>
<button>Return to list</button>
</Link>
</div>
);
};
// App router compoment.
function App() {
return (
<div className="App">
<Router>
<div>
<Route exact path="/cards" component={Cards} />
<Route path="/cards/:id" component={Card} />
</div>
</Router>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
_
これに対するもう1つの可能な解決策は、/cards/:id
全画面モーダルとしてルーティングし、/cards
背後にマウントされたルート
Reduxを使用したfull implementationの場合、これは CodeSandbox で確認できます。
履歴APIを利用してこれを行いました。
ルート変更後のスクロール位置を保存します。
ユーザーが戻るボタンをクリックしたときにスクロール位置を復元します。
スクロール位置をgetSnapshotBeforeUpdate
に保存し、componentDidUpdate
に復元します。
// Saving scroll position.
getSnapshotBeforeUpdate(prevProps) {
const {
history: { action },
location: { pathname }
} = prevProps;
if (action !== "POP") {
scrollData = { ...scrollData, [pathname]: window.pageYOffset };
}
return null;
}
// Restore scroll position.
componentDidUpdate() {
const {
history: { action },
location: { pathname }
} = this.props;
if (action === "POP") {
if (scrollData[pathname]) {
setTimeout(() =>
window.scrollTo({
left: 0,
top: scrollData[pathname],
behavior: "smooth"
})
);
} else {
setTimeout(window.scrollTo({ left: 0, top: 0 }));
}
} else {
setTimeout(window.scrollTo({ left: 0, top: 0 }));
}
}