一次简单的 react 无限瀑布流使用优化
一、问题
最近用 react 写一个无限瀑布流,发现当数据变多的时候非常卡顿,并且会出现闪烁情况。
而在 PC 浏览器上没发现什么卡顿情况,在手机H5上出现的卡顿,有点严重。
二、场景
主要场景描述一下,最外层容器主要是负责数据请求等操作,组件为 AppWrapper
。
AppWrapper
在请求完数据之后,会进行一次 setState,将 list 通过 props 传递给 WaterFall
组件。
WaterFall
组件本身拥有 renderItem
prop,用来渲染每个内容。
每个内容卡片由三部分组成:封面图、标题、底部用户信息和点赞操作。
内容卡片分为多个类型,每个类型的视觉唯一区别集中在 封面图。
组件关系如下:
三、最开始的粗暴行为
最开始开发没有考虑性能,直接往上面怼,处理逻辑如下:
- 在
AppWrapper
的 componentWillMount 中请求数据,并完成一次 setState - 在
AppWrapper
组件中判断,当thsi.state.list.length > 0
的时候渲染WaterFall
组件,将 list 传入 WaterFall - 在
WaterFall
组件的renderItem
方法中判断并且组装不同的卡片,并将 每个卡片的信息通过 this.props.info 传入每个卡片 - 每个卡片都有
Cover 组件
、Title 组件
、UserInfo 组件
三部分拼成,其中Cover
组件可能存在不同的类型,比如PicCover
orVideoCover
等
上面的处理逻辑看起来是没有什么问题的,所有的内容均通过 porp 向下面传递。
比较特殊的是在 UserInfo
组件中,存在点赞操作,每次点赞或者取消点赞之后,都会触发一次网络请求,然后会执行一个 prop 回调,传入 id,并在整个 list 中查找这个 id,修改点赞的数量,然后将整个 List 进行一次 setState 操作。
四、粗暴行为带来的问题
每页返回20条数据,最开始的时候是没有问题的,但是当进行无限瀑布流加载之后,发现每次加载都非常卡顿。
无限瀑布流加载的规则无非是当页面滚动到底部后再次请求,然后将数据 push 到 this.state.list 中,然后进行一次 setState。
然后就是上面的操作,导致在手机上非常卡顿。
Title
组件经常会出现闪烁的问题。
五、简单的优化
已经保证了每个卡片的 key
只是简单优化,保证了不闪烁等问题,并没有优化太多,其实可优化的地方还有很多,最早的时候我是按照卡片类型去写卡片组件,而不是将卡片的内容进行拆分。
优化主要是从
shouldComponentUpdate
入手
1、UserInfo 包含点赞的组件
优化前:
所有内容信息都是从 props 获取,本地没有 state,点赞状态和点赞数量的变化依赖执行的回调中的 setState 的改变。
优化后:
第一次获取点赞状态和点赞数量是从 props 中获取,直接写入本地 state,点赞或取消点赞不去执行回调,也就不进行 setState。
同时 shouldComponentUpdate
中更新规则如下:
shouldComponentUpdate(nextProps, nextState) {
// console.log(this.state.favourStatus, nextState.favourStatus);
return this.state.favourStatus !== nextState.favourStatus;
}
只有点赞状态变更之后,再会进行重新渲染,否则无论 props 怎么更新,UserInfo 组件是不关心的。
这也就保证了,当我在无限加载瀑布流的时候,即使触发 setState 了,点赞状态和数量也不会丢失,根本不需要在点赞或者移除点赞的时候去 setState。
2、Cover 组件和 Title 组件
即使 Cover 组件有许多个不同的类型页不需要去更新,只需要渲染一次就 OK 了,Title 组价也是如此,因此这两类组件的更新都是 false.
shouldComponentUpdate(nextProps, nextState) {
return false;
}
3、整个 WaterFall 组件
因为页面上不仅仅有 WaterFall 组件,因此需要保证,只有当瀑布流的 list 发生变化的时候才会进行 WaterFall 组件的更新。
因为我的场景中不存在下拉刷新
,只有上拉加载
,因此组件更新策略很简单:
shouldComponentUpdate(nextProps, nextState) {
return nextProps.list.length !== this.props.length;
}
如果涉及到下拉刷新的 WaterFall 组件,则不能仅仅通过长度去判断,而是应当通过一个标志去判断,我记得我曾经有一个做法是在 AppWrapper
中设定一个 state: { refreshing: false }
,将这个 refreshing 传递给 WaterFall 组件,并且修改 shouldComponentUpdate:
shouldComponentUpdate(nextProps, nextState) {
return nextProps.refreshing || nextProps.list.length !== this.props.length;
}
文章版权:Postbird-There I am , in the world more exciting!
本文链接:http://ptbird.cn/react-water-better-simple.html
转载请注明文章原始出处 !
好好学习,打卡!