[英]Maintaining state and scroll position in react
我正在尝试构建一个显示博客文章列表的组件。 当用户单击帖子时,它会呈现显示帖子详细信息的组件。 但是当用户在浏览器中点击后退按钮时,前一个带有帖子列表的组件会重新呈现,它会丢失前一个 state 并滚动 position。 Is there a way that I Can save the previous state and the scroll position so that when a user hits the back button they are at the same position and the post list is not re-rendered and doesn't loose the scroll position too?
这是我的博客列表组件代码:
import axios from "axios";
import { Link } from "react-router-dom";
class About extends React.Component {
state = { posts: [] };
componentDidMount() {
axios.get("https://jsonplaceholder.typicode.com/posts").then(res => {
this.setState({ posts: res.data.slice(0, 10) });
});
}
render() {
const { posts } = this.state;
const postsList = posts.length ? (
posts.map(post => {
return (
<div className="card" key={post.id}>
<div className="card-body">
<Link to={"/view/" + post.id}>
<h5 className="card-title">{post.title}</h5>
</Link>
<p className="card-text">{post.body}</p>
</div>
</div>
);
})
) : (
<div className="text-danger text-center">No Posts yet...</div>
);
return <div>{postsList}</div>;
}
}
export default About;
这是我的博客详细信息组件:
import React from "react";
import { withRouter } from "react-router-dom";
import axios from "axios";
class PostDetail extends React.Component {
state = { post: null };
componentDidMount() {
let id = this.props.match.params.post_id;
axios.get("https://jsonplaceholder.typicode.com/posts/" + id).then(res => {
this.setState({ post: res.data });
});
}
render() {
const post = this.state.post ? (
<div className="card border-primary">
<div className="card-header">{this.state.post.title}</div>
<div className="card-body text-primary">
<p className="card-text">{this.state.post.body}</p>
</div>
</div>
) : (
<div className="text-center text-danger">Loading Post...</div>
);
return <div>{post}</div>;
}
}
export default withRouter(PostDetail);
您必须使用window.pageYOffset
在点击帖子时将滚动位置存储在state
this.setState({
scrollPosition: window.pageYOffset
});
一旦你点击后退按钮,你必须在componentDidMount
的方法中设置窗口位置。
window.scrollTo(0, this.state.scrollPosition);
默认情况下,您可以将scrollPosition
的值设置为0
。
更新
出于演示目的,我在这里使用sessionStorage
来维护滚动位置。 您还可以使用上下文 API 或 redux 存储来管理它。
这是为您准备的工作演示。 https://stackblitz.com/edit/react-fystht
import React from "react";
import axios from "axios";
import { Link } from "react-router-dom";
class Posts extends React.Component {
state = { posts: [] };
componentDidMount() {
axios.get("https://jsonplaceholder.typicode.com/posts").then(res => {
this.setState({ posts: res.data.slice(0, 20) }, () => {
this.handleScrollPosition();
});
});
}
// handle scroll position after content load
handleScrollPosition = () => {
const scrollPosition = sessionStorage.getItem("scrollPosition");
if (scrollPosition) {
window.scrollTo(0, parseInt(scrollPosition));
sessionStorage.removeItem("scrollPosition");
}
};
// store position in sessionStorage
handleClick = e => {
sessionStorage.setItem("scrollPosition", window.pageYOffset);
};
render() {
const { posts } = this.state;
const postsList = posts.length ? (
posts.map(post => {
return (
<div className="card" key={post.id}>
<div className="card-body">
<Link to={"/view/" + post.id} onClick={this.handleClick}>
<h5 className="card-title">{post.title}</h5>
</Link>
<p className="card-text">{post.body}</p>
</div>
</div>
);
})
) : (
<div className="text-danger text-center">No Posts yet...</div>
);
return <div>{postsList}</div>;
}
}
export default Posts;
希望能帮到你!
这是使用钩子(功能组件)的答案
import axios from 'axios';
import { Link } from 'react-router-dom';
const Posts = () => {
const [posts, setPosts] = useState([]);
const postsList = posts.length;
useEffect(() => {
axios.get('https://jsonplaceholder.typicode.com/posts').then((res) => {
setPosts(res.data.slice(0, 20));
});
}, []);
useEffect(() => {
if (posts.length) {
const scrollPosition = sessionStorage.getItem('scrollPosition');
if (scrollPosition) {
window.scrollTo(0, parseInt(scrollPosition, 10));
sessionStorage.removeItem('scrollPosition');
}
}
}, [posts]);
return (
<>
{postsList ? (
posts.map((post) => {
return (
<div className="card" key={post.id}>
<div className="card-body">
<Link
to={'/view/' + post.id}
onClick={() =>
sessionStorage.setItem('scrollPosition', window.pageYOffset)
}
>
<h5 className="card-title">{post.title}</h5>
</Link>
<p className="card-text">{post.body}</p>
</div>
</div>
);
})
) : (
<div className="text-danger text-center">No Posts yet...</div>
)}
<div>{postsList}</div>
</>
);
};
export default Posts;
只需检查上一个 URL 并调用 API:
import React, {Component} from 'react';
import axios from "axios";
import { Link } from "react-router-dom";
class About extends React.Component {
constructor() {
super();
this.state = {
posts: [],
};
}
componentDidMount() {
var url = document.referrer
if (url && !url.includes("/view/")) {
axios.get("https://jsonplaceholder.typicode.com/posts").then(res => {
this.setState({
posts: res.data.slice(0, 10),
isAboutPageOpen: true
});
});
}
}
render() {
const { posts } = this.state;
const postsList = posts.length ? (
posts.map(post => {
return (
<div className="card" key={post.id}>
<div className="card-body">
<Link to={"/view/" + post.id}>
<h5 className="card-title">{post.title}</h5>
</Link>
<p className="card-text">{post.body}</p>
</div>
</div>
);
})
) : (
<div className="text-danger text-center">No Posts yet...</div>
);
return <div>{postsList}</div>;
}
}
export default About;
以防万一,有人想对某些特定的 HTML 元素做同样的事情。
const scrollYPosition = document.getElementsByClassName('grid-body')[0].scrollTop;
this.setState({
toBeExpanded
},() => {
document.getElementsByClassName('grid-body')[0].scrollTo(0, scrollYPosition);
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.