基于React与Redux的留言墙的实现
背景
由于某事业群需要留言墙用于年会,同时需要调用大象公众号服务器接口,所以在今年年初开发了留言墙用于活动现场交流。
设计
本次留言墙分为两部分。一部分为活动展示部分,另一部分为后台审批部分。
活动展示部分为匿名留言墙形式(后改为实名制),需要根据收到的留言墙进行向上平滑滚动,如果没有消息接收则停止在最后一条消息上。
后台审批部分为管理人员对用户像某个特定公众号发送的特定格式消息进行审核,符合上墙要求的消息则通过审核,通过活动展示页面进行展示。
技术方案
React
该项目采用了React作为View层的渲染框架。关于React的简单介绍,大家可以戳阮一峰的博客React 入门实例教程, 需要系统学习的同学可以戳React的官方网站React英文版,React中文版。建议大家阅读React英文版网站,中文版网站相对于英文版网站来说缺少了一部分内容,例如React的children部分,可能是由于英文文档更新导致的翻译不太及时的原因。
Redux
Redux的学习可以通过Redux中文文档来进行。里面有很多的示例能够辅助进行学习。具体使用方法会通过后面的步骤进行介绍。
实现
React
在View层中,有两个组件。
Message
<div className="message">{this.props.flag === false ? <img src={this.props.photo} alt="头像"/> : ''}<div className="message-content">{this.props.uname} [{this.parseDate(this.props.sendTime)}] {this.props.text}{this.props.flag === true ? this.props.approve === 0 ?<button onClick={this.props.approveMsg}>通过</button> : '已通过' : ''}</div></div>
MsgList
<div><button onClick={(e)=>{this.handleClick(e)}}>获取消息</button><div id="wall"><ul>{this.props.msgs.map((message, index) =><Message {...message} key={index} flag={this.props.flag}approveMsg={()=>{this.props.approveMsg(index, message.id)}}/>)}</ul></div></div>
其中Message为每条消息的组件,MsgList为整个消息列表的组件。
Redux
Action
Action主要为处理数据的数据层。大部分的数据操作都放在Action中,通过dispatch(Action)的方法来通知readucer进行数据更新,从而通过react-redux来通知组件更新。
首先,会定义一些Action常量,用于操作命名。
export const WALL_REQUEST = 'WALL_REQUEST';
export const WALL_REQUEST_SUCCESS = 'WALL_REQUEST_SUCCESS';
export const WALL_REQUEST_FAIL = 'WALL_REQUEST_FAIL';export const CHECK_MSGS = 'CHECK_MSGS';
export const CHECK_MSGS_SUCCESS = 'CHECK_MSGS_SUCCESS';
export const CHECK_MSGS_FAIL = 'CHECK_MSGS_FAIL';
export const MSG_REQUEST = 'MSG_REQUEST';
export const MSG_REFUSE = 'MSG_REFUSE';
export const MSG_PASS = 'MSG_PASS';
同时,会定义一些函数,用于View层中与Action部分进行通信,从而触发某些操作。
export function fetchMsgs(number) {const path = '/nh/show/msg';return dispatch=> {dispatch(requestMsgs(number));return window.fetch(URL + path).then(response=>response.json()).then(json=>dispatch(receiveMsgs(json.data)));}
}
在reducer中使用了window变量中的fetch接口用于数据获取,有关于此接口的使用我后面会写另一篇文章来进行介绍,大家如果需要资料可以先戳此处,需要中文版的童鞋可以戳此处。
Reducer
在Reducer中,会对当前state中的所有数据进行处理,改变state中的全局数据从而驱动组件重新渲染。
function msgsReducer(state = [], action) {switch(action.type) {case WALL_REQUEST:{return state.slice(action.number)}case WALL_REQUEST_SUCCESS:{return [...state, ...action.data]}default:{return state;}}
}
在reducer中一般通过Action中声明的操作和action所带来的参数对state进行操作。每次都需要返回一个新的对象或者数组,而不能再原有数据上进行修改,从而避免数据更新后组件不更新的问题。
Server
server端返回的数据为一次性数据,即数据取过后就不会再返回,因此需要在前端Reducer里面对数据进行存储。由于数据为滚动显示,因此需要一个队列来进行控制。
难点
滚动问题
scrollTop+setInterval
最开始的滚动方案选择此方案。此方案在实现上也最为简单。但是,当消息数目到达1K量级时,能够明显的感觉到有卡顿的现象发生,滚动很不流畅,因此抛弃了此方法。
transform+setInterval
由于上一个方案中scrollTop在节点数过多的情况下会导致卡顿的问题,因此在滚动上采用了transform的方法,但是由于setInterval粒度不够小,因此对其进行了替换。
transform+window.requestAnimationFrame
window.requestAnimationFrame是浏览器接口,被调用的频率是每秒60次,但是一般会遵循W3C标准规定的频率。使用此接口可以保证调用频率,同时能够配合transform的变化数字来进行速度控制。因此采用了此方法。
节点删除功能
由于在留言墙的使用过程中,会有不断的新的节点产生并且滚动出视口,因此为了节省内存,需要将滚动出视口的节点删除,从而避免整个网页消耗的内存越来越大。
由于滚动方式确定为transform的滚动方式,因此选择了在请求调用返回数据后同时触发删除代码,对当前消息节点进行判断,对已经滚动到视口外的数据节点进行删除,并重置transform值,从而达到删除节点的目的。
componentWillReceiveProps(nextProps) {if(this.props.flag === false && this.props.msgs.length !== nextProps.msgs.length) {let number = Math.floor((-this.y) / this.msgHeight),element = document.getElementById('wall').getElementsByTagName('ul')[0];if(number > 0) {this.y = this.y + number * this.msgHeight;element.style.transform = 'translateY(' + (this.y) + 'px)';return;}window.cancelAnimationFrame(this.animationId);this.animationId = window.requestAnimationFrame(this.scroll.bind(this));}
}
通过组件接收新数据渲染时来重置transform值,完成节点删除工作。
不足
如果消息并发数量较多,会导致消息堆积在视口下方等待向上滚动,由此可能消耗大量的内存,后续仍然需要优化,避免所有接受到的未展示的数据都渲染出来堆积在下方。
总结
在刚开始设计时至少考虑到了滚动的情况,并没有考虑到消息越来越多导致页面占用内存越来越大的问题。当完成最初版本的消息滚动时,在自己测试的过程中因为消息数量过大导致卡顿,所以考虑到了滚动方面的优化与节点删除的问题。transform的效率优于scrollTop,而window.requestAnimationFrame的性能又优于setInterval,但是在开发时间上不是特别充足,因此选择了性能最好的技术方案,但是舍弃了一部分优化的方案。
基于React与Redux的留言墙的实现相关推荐
- 基于 React 和 Redux 的现代内容编辑器 ORY Editor
ORY Editor 详细介绍 https://yqfile.alicdn.com/a0451975a0e3e87ddae75fb5fbb54a150a6e971b.png" > OR ...
- 基于 react, redux 最佳实践构建的 2048
前段时间 React license 的问题闹的沸沸扬扬,搞得 React 社区人心惶惶,好在最终 React 团队听取了社区意见把 license 换成了 MIT.不管 React license ...
- 实例讲解基于 React+Redux 的前端开发流程
前言:在当下的前端界,react 和 redux 发展得如火如荼,react 在 github 的 star 数达 42000 +,超过了 jquery 的 39000+,也即将超过前几年比较火的an ...
- 基于react的影院购票应用
写在最前 这次使用react&redux,来模拟了一个购票app,需要关注的是本次全部数据均为mock实现,不涉及后台.同时其中不会涉及react与redux的语法,只关注到一些模拟原生效果的 ...
- 前段react技术架构图_基于 React 的可视化编辑平台实践
前言 前段时间发在朋友圈的一句话:各种自主搭建的平台,想起好多年各种DIY博客,行业门户网站,本质不变,变的是实现的手段了. 正文从这开始-- 本文主要介绍了基于 React 构建可视化编辑平台的实践 ...
- Mdebug:基于React开发的移动web调试工具
作者:thinkchen,腾讯 PCG 高级前端开发工程师 mdebug是腾讯新闻 TNTWEB 团队推出的基于React开发的新的web调试工具, 沉淀自腾讯新闻微信手 q 双插件多年的移动 web ...
- 一个基于 React 开发的PC端音乐App
?一个基于 React 开发的PC端音乐App. 同时支持 Mac 与 Windows 系统.下载地址 项目使用 electron 作为外壳,webpack 作为打包工具,核心技术包括 React + ...
- Rekit Studio简介:用于React和Redux开发的真实IDE
by Nate Wang 内特·王 Rekit Studio简介:用于React和Redux开发的真实IDE (Introducing Rekit Studio: a real IDE for Rea ...
- 基于React+Koa实现一个h5页面可视化编辑器-Dooring
前言 前段时间笔者一直忙于数据可视化方面的工作,比如如何实现拖拽式生成可视化大屏,如何定制可视化图表交互和数据导入方案等,这块需求在B端企业中应用非常大,所以非常有探索价值. 本篇文章并非和数据可视化 ...
最新文章
- WebApi接口 - 响应输出xml和json
- Java集合框架之ArrayList类
- 第三方应用如何在SAP Kyma上进行服务注册
- 阿里巴巴研究员刘国华:阿里巴巴智能运维体系建设
- 超详细的python语法要点思维导图,看了直呼相见恨晚,拿走不谢
- 伍斯特理工学院计算机研究生,伍斯特理工学院计算机工程硕士排名第52(2020年TFE Times排名)...
- 案例分析:从误删除数据库血案看数据库系统的安全设计
- k8s执行init时出现 Initial timeout of 40s passed
- problem: ERROR cluster.YarnClientSchedulerBackend: Yarn application has already exited with state
- ios 图表_在ios应用中实现蜘蛛网图表
- 华为云CDN加速服务:让你体验不一样的云提速
- 耗时十个月的德国APS,教会我的学习方法
- 1M带宽服务器能够承载多少人
- 圣天诺 加密java_圣天诺Sentinel LDK 7.8壳加密的编译环境是什么?
- 戴记严选GM3323D 鼠标左右键失效 解决办法
- htc+one+m8+联通+android+5,HTC One M8e 双卡版 刷机包 Android5.0.2+Sense6 完美ROOT 下拉农历 精简稳定版...
- 【纯干货】标题里的大学问,月薪10000元以上的运营,是这样写宝贝标题的
- XPath下载与安装
- Maven打包问题归纳
- GPRS模块的使用与相应SOCKET服务器的搭建