在使用react搭配react-router做应用的时候,你可能遇到这样的问题,当我从第一个页面过渡到第二个页面,然后返回之后,发现之前的页面的状态全部不见了,即回到了初始的状态。

这点在页面存在多个TAB页或者多条件筛选的时候体验会更加明显,这时候我又不得不点击我之前选择的页签,重新选择筛选条件,然后再进行搜索。因此,在这种情况下,保存之前的状态显得尤为亟待解决,下面是自己实践出来的几种方法,做一下分享,同时希望和各位一起探讨,看能不能有什么更好的办法。

代码:github

  1. // normal/routers/Books/Books.js
  2. module.exports = {
  3. path: 'books',
  4. getComponent(nextState, cb) {
  5. require.ensure([], (require) => {
  6. cb(null, require('./components/Books'))
  7. })
  8. },
  9. getChildRoutes(partialNextState, cb) {
  10. require.ensure([], (require) => {
  11. cb(null, [
  12. require('./book')
  13. ])
  14. })
  15. }
  16. };
  17. // normal/routers/Books/book.js
  18. module.exports = {
  19. path: 'book/:id',
  20. getComponent(nextState, cb) {
  21. require.ensure([], (require) => {
  22. cb(null, require('./components/Book'))
  23. })
  24. }
  25. };

配置图书列表下的嵌套路由可以查看图书详情。具体的路由跳转如下:

  1. // normal/routers/Books/components/Books.js
  2. onLookDetail(id, book, index) {
  3. this.setState({ activeIndex: index });
  4. this.props.router.push({ pathname: `books/book/${id}`, query: book });
  5. }
  6. render() {
  7. const { children } = this.props;
  8. // ...
  9. // 如果有字路由组件,就渲染子组件
  10. if (children) {
  11. return children;
  12. }
  13. // ...
  14. }

效果如下:

child-router

可以看到,当从详情页面返回时,点击的激活状态依旧可以保存,但是列表滚动的高度并不能够保存,关于高度的恢复在下面会讲到。

不占用路由,在当前页面直接已弹窗的形式加载详情页面。

  1. // normal/routers/Books/components/Books.js
  2. constructor(props) {
  3. super(props);
  4. this.state = {
  5. activeIndex: -1,
  6. books: [],
  7. modal: false
  8. };
  9. }
  10. onLookDetail(id, book, index) {
  11. this.setState({ activeIndex: index, modal: true });
  12. }
  13. onDetailBack() {
  14. this.setState({ modal: false });
  15. }
  16. render() {
  17. {
  18. // 根据state中的modal值来判断当前弹窗是否显示
  19. // 其实就是Book.js中的代码
  20. modal && (
  21. <div style={ styles.modal }>
  22. <Flex direction="column" style={ styles.wrapper }>
  23. <div style={ styles.header }>
  24. <NavBar
  25. mode="dark"
  26. leftContent="返回"
  27. icon={<Icon type="left" />}
  28. onLeftClick={ this.onDetailBack.bind(this) }>
  29. 图书详情
  30. </NavBar>
  31. </div>
  32. <div style={ styles.content }>
  33. <Card>
  34. <Card.Header
  35. title="标题"
  36. thumb="xxx"
  37. extra={ <span>{ book.title }</span> }/>
  38. <Card.Body>
  39. <div>{ book.description }</div>
  40. </Card.Body>
  41. <Card.Footer
  42. content="footer content"
  43. extra={<div>{ book.price }</div>} />
  44. </Card>
  45. </div>
  46. </Flex>
  47. </div>
  48. )
  49. }
  50. }

效果如下:

modal

看上去效果十分好,既能保存状态,也能保存滚动条的高度。

我把这三种方案归结为一种,因为实际上是在离开列表组件的时候保存当前的状态,然后在回到页面的时候根据之前保存的状态来进行现场恢复而已。

  1. // src/routers/Books/components/Books.js
  2. // 配合shouldComponentUpdate声明周期函数,避免不必要的渲染
  3. shouldComponentUpdate(nextProps, nextState) {
  4. return !is(fromJS(this.props.books), fromJS(nextProps.books))
  5. || !is(fromJS(this.state), fromJS(nextState));
  6. }
  7. // 更新当前选中的activeIndex值,将其同步至redux中,然后再进行路由跳转
  8. onLookDetail(id, book, index) {
  9. const { actions } = this.props;
  10. actions.updateBooks({ activeIndex: index });
  11. this.props.router.push({ pathname: `book/${id}`, query: book });
  12. }
  13. // 从redux中取值进行现场恢复
  14. render() {
  15. const { books } = this.props;
  16. const list = books.books;
  17. const activeIndex = books.activeIndex;
  18. // ...
  19. }
  20. // src/reudx/reudcers/books.js
  21. const initialState = {
  22. books: [],
  23. activeIndex: -1
  24. };

效果如下:

redux

效果和字路由方式相同,依然存在滚动高度不能保存的问题。

下面来谈谈如何解决滚动高度的问题,综合起来还是一种恢复现场的方式。在页面即将离开之前,保存之前的scrollTop值,然后再次回到这个页面的时候,恢复滚动高度即可。

  1. // src/reudx/reudcers/books.js
  2. const initialState = {
  3. books: [],
  4. activeIndex: -1,
  5. // 添加scrollTop
  6. scrollTop: 0
  7. };
  8. // src/routers/Books/components/Books.js
  9. componentDidMount() {
  10. const { actions, books } = this.props;
  11. const content = this.refs.content;
  12. const scrollTop = books.scrollTop;
  13. if (scrollTop > 0) {
  14. content.scrollTo(0, scrollTop);
  15. }
  16. setTimeout(() => {
  17. actions.getBooks();
  18. }, 150);
  19. }
  20. componentWillUnmount() {
  21. const content = this.refs.content;
  22. const { actions } = this.props;
  23. actions.updateBooks({ scrollTop: content.scrollTop });
  24. }

效果如下:

scrollTop

github上搜索看到了这个库,类似于react-router的一个翻版,同时在react-router的基础上增加了类似于vue-router中的keep-alive功能,这点暂时占坑,等做了案例之后再来填坑。

版权声明:本文为rynxiao原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/rynxiao/p/8305017.html