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

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

代码:github

解决方案一:子路由方式

// normal/routers/Books/Books.js
module.exports = {
path: 'books',
getComponent(nextState, cb) {
require.ensure([], (require) => {
cb(null, require('./components/Books'))
})
},
getChildRoutes(partialNextState, cb) {
require.ensure([], (require) => {
cb(null, [
require('./book')
])
})
}
}; // normal/routers/Books/book.js
module.exports = {
path: 'book/:id',
getComponent(nextState, cb) {
require.ensure([], (require) => {
cb(null, require('./components/Book'))
})
}
};

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

// normal/routers/Books/components/Books.js

onLookDetail(id, book, index) {
this.setState({ activeIndex: index });
this.props.router.push({ pathname: `books/book/${id}`, query: book });
} render() {
const { children } = this.props;
// ... // 如果有字路由组件,就渲染子组件
if (children) {
return children;
}
// ...
}

效果如下:

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

解决方案二:当前页面弹窗

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

// normal/routers/Books/components/Books.js
constructor(props) {
super(props);
this.state = {
activeIndex: -1,
books: [],
modal: false
};
} onLookDetail(id, book, index) {
this.setState({ activeIndex: index, modal: true });
} onDetailBack() {
this.setState({ modal: false });
} render() {
{
// 根据state中的modal值来判断当前弹窗是否显示
// 其实就是Book.js中的代码
modal && (
<div style={ styles.modal }>
<Flex direction="column" style={ styles.wrapper }>
<div style={ styles.header }>
<NavBar
mode="dark"
leftContent="返回"
icon={<Icon type="left" />}
onLeftClick={ this.onDetailBack.bind(this) }>
图书详情
</NavBar>
</div>
<div style={ styles.content }>
<Card>
<Card.Header
title="标题"
thumb="xxx"
extra={ <span>{ book.title }</span> }/>
<Card.Body>
<div>{ book.description }</div>
</Card.Body>
<Card.Footer
content="footer content"
extra={<div>{ book.price }</div>} />
</Card>
</div>
</Flex>
</div>
)
}
}

效果如下:

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

解决方案三:本地存储/redux数据仓库/参数传递

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

// src/routers/Books/components/Books.js

// 配合shouldComponentUpdate声明周期函数,避免不必要的渲染
shouldComponentUpdate(nextProps, nextState) {
return !is(fromJS(this.props.books), fromJS(nextProps.books))
|| !is(fromJS(this.state), fromJS(nextState));
} // 更新当前选中的activeIndex值,将其同步至redux中,然后再进行路由跳转
onLookDetail(id, book, index) {
const { actions } = this.props;
actions.updateBooks({ activeIndex: index });
this.props.router.push({ pathname: `book/${id}`, query: book });
} // 从redux中取值进行现场恢复
render() {
const { books } = this.props;
const list = books.books;
const activeIndex = books.activeIndex; // ...
} // src/reudx/reudcers/books.js
const initialState = {
books: [],
activeIndex: -1
};

效果如下:

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

滚动高度问题

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

// src/reudx/reudcers/books.js
const initialState = {
books: [],
activeIndex: -1,
// 添加scrollTop
scrollTop: 0
}; // src/routers/Books/components/Books.js
componentDidMount() {
const { actions, books } = this.props;
const content = this.refs.content;
const scrollTop = books.scrollTop; if (scrollTop > 0) {
content.scrollTo(0, scrollTop);
} setTimeout(() => {
actions.getBooks();
}, 150);
} componentWillUnmount() {
const content = this.refs.content;
const { actions } = this.props;
actions.updateBooks({ scrollTop: content.scrollTop });
}

效果如下:

尝试方案:react-keeper

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

关于React中状态保存的研究的更多相关文章

  1. Android Activity中状态保存机制

    在Activity中保存用户的当前操作状态,如输入框中的文本,一般情况下载按了home键后,重新进入文本框中的东西会丢下,所以我们要保存当前页面信息,如在写短信的时候接到一个电话,那么当你接电话的时候 ...

  2. 【React】377- 实现 React 中的状态自动保存

    点击上方"前端自习课"关注,学习起来~ 作者:陈俊宇 https://github.com/CJY0208 什么是状态保存? 假设有下述场景: 移动端中,用户访问了一个列表页,上拉 ...

  3. Android菜鸟的成长笔记(15)—— Android中的状态保存探究(下)

    原文:Android菜鸟的成长笔记(15)-- Android中的状态保存探究(下) 在上一篇中我们简单了解关于Android中状态保存的过程和原理,这一篇中我们来看一下在系统配置改变的情况下保存数据 ...

  4. react中界面跳转 A界面跳B界面,返回A界面,A界面状态保持不变 redux的state方法

    在上一篇文章中说过了react中界面A跳到B,返回A,A界面状态保持不变,上篇中使用的是传统的localStorage方法,现在来使用第二种redux的state方法来实现这个功能 现在我刚接触red ...

  5. android中正确保存view的状态

    英文原文: http://trickyandroid.com/saving-android-view-state-correctly/ 转载此译文须注明出处. 今天我们聊一聊安卓中保存和恢复view状 ...

  6. Android菜鸟的成长笔记(14)—— Android中的状态保存探究(上)

    原文:[置顶] Android菜鸟的成长笔记(14)—— Android中的状态保存探究(上) 我们在用手机的时候可能会发现,即使应用被放到后台再返回到前台数据依然保留(比如说我们正在玩游戏,突然电话 ...

  7. React 中的 Component、PureComponent、无状态组件 之间的比较

    React 中的 Component.PureComponent.无状态组件之间的比较 table th:first-of-type { width: 150px; } 组件类型 说明 React.c ...

  8. react篇章-React State(状态)-将生命周期方法添加到类中

    将生命周期方法添加到类中 在具有许多组件的应用程序中,在销毁时释放组件所占用的资源非常重要. 每当 Clock 组件第一次加载到 DOM 中的时候,我们都想生成定时器,这在 React 中被称为挂载. ...

  9. React中的高阶组件,无状态组件,PureComponent

    1. 高阶组件 React中的高阶组件是一个函数,不是一个组件. 函数的入参有一个React组件和一些参数,返回值是一个包装后的React组件.相当于将输入的React组件进行了一些增强.React的 ...

随机推荐

  1. GIS前端将选中的图形输出为Shapfile文件

    老师让我实现如题的功能,我对着ArcGIS js api找了半天,没有发现该方法接口,找了很多资料,前后问了三个前辈. 第一个前辈说用GP服务,我在ArcMap的工具箱里找到convert to la ...

  2. spring boot https --restful接口篇

    我们写的接口默认都是http形式的,不过我们的接口很容易被人抓包,而且一抓全是明文的挺尴尬的 spring boot配置https生成证书大的方向有3种: 1.利用keytool自己生成证书 2.从免 ...

  3. 【python】元组

    Python 3.6.0 (v3.6.0:41df79263a11, Dec 23 2016, 07:18:10) [MSC v.1900 32 bit (Intel)] on win32Type & ...

  4. Lvs+keepAlived实现负载均衡高可用集群(DR实现)

    第1章 LVS 简介 1.1 LVS介绍 LVS是Linux Virtual Server的简写,意为Linux虚拟服务器,是虚拟的服务器集群系统,可在UNIX/LINUX平台下实现负载均衡集群功能. ...

  5. 如何在markdown中插入表情

    Markdown是很好用的呀,个人灰常的喜欢,也是灰常漂亮的,但是如何在写文章的时候插入表情呢,下面给出一部分代码

  6. 视觉SLAM的数学表达

    相机是在某些时刻采集数据的,所以只关心这些时刻的位置和地图. 就把这一段时间的运动变成了李三时刻 t=1,2,...K当中发生的事情. 在这些事可,x表示机器自身的位置. x1,x2,x3,x4... ...

  7. bzoj 4537 HNOI2016 最小公倍数

    Description 给定一张N个顶点M条边的无向图(顶点编号为1,2,-,n),每条边上带有权值.所有权值都可以分解成2^a*3^b的形式.现在有q个询问,每次询问给定四个参数u.v.a和b,请你 ...

  8. vue过滤数字为2位小数点,过滤器

    过滤数字为2位小数点 filters: { //保留2位小数点过滤器 不四舍五入 number(value) { var toFixedNum = Number(value).toFixed(3); ...

  9. HBase跨地区机房的压测小程序——从开发到打包部署(图文版)

    今天做了一个跨地区机房的压测小程序,主要的思路就是基于事先准备好的rowkey文件,利用多线程模拟并发的rowkey查询,可以实现并发数的自由控制.主要是整个流程下来,遇到了点打包的坑,所以特意记录下 ...

  10. UTC 通用格式时间 转换为 时间戳,并格式化为2017-01-01 12:00:00

    在使用阿里云oss获取文件列表是,发现时间格式是这样的 2016-09-20T13:45:04.000Z (尼玛,是什么鬼), 经过度娘的解答,发现这就是传说中的 UTC通用格式时间 问题来了,怎么转 ...