你们伙儿们,又见面了?。 自上次Byemess Todo以后,以为自身不足仍是挺多的,期间又萌生了一些将它重构加上更多新特性的想法,以后技术磨炼一阵再来好好改造它。对于Learn by doing这种事情,一次就会上瘾啊有木有❤️,因而乎本着继续精进练习React技术栈,以及实践更多相关技术的初衷,besides that,本身还想再准备一个小项目来为找工做打底气,因而乎就有了CoderPad。react
在最开始的时候,是想作一个催稿app,又是一个集成的idea:提供分类书单,能够记录阅读状况,而后根据这个状况设定或者后台计算智能推荐:什么时候去写一篇相关的博客(技术博客),固然写做也是在这个app里完成,而后自动部署至github page。 名字我都想好了,就叫催乎...(知乎er们懂的),奈何这是个大工程啊... 我就造出了这么个只有编辑,阅读的阉割版。 另外关于写完markdown直接部署生成静态博客的app我推荐好基友的Page.qy => ? 无代码建站,基于Node.js,React和Electron,很用心的app,向他学习之,他立刻又会写出一个UI逆天美的音乐播放器了,大家能够关注他。ios
Markdown: 支持本地缓存,保存/删除/查看/下载,追求极简。nginx
NewsFeed: 集成v2ex,HackerNews-Top Stories, Github-Trendinggit
Music: 暂未施工github
老朋友React全家桶: 对于这块,值得一提的是react router v4,相对于v3的巨大改动,extremely make sense. 让route与组件化思想更贴切,有种幻觉:定义子route更加为所欲为了。至于为何... 请君上手感觉。express
Immutable: 有一些细微的坑,主要体如今数据类型转化上,immutable会将原生JS数据类型进行包装,如Map,List,在对它们进行提取的时候须要注意是否已经转化为原生JS,不然容易出错。 个人建议就是时刻注意提取的数据是什么类型,结合PropTypes进行参数检测,出错时先console看看,通常很快能够解决。 对于多层对象嵌套的时候,为了保险,手动将被嵌套的对象进行指定类型转化,好比{ list: [] } => { list:Immutable.List([]) }
,若是要偷懒的话能够直接使用fromJS
,可是这个方法渗透性强,会将全部内嵌结构进行转化,在本项目的后期重构里就遇到了子数组遍历出来全是immutable object的状况,须要手动再次转化,非常恶心。 这些缺点在redux文档里也有表述,在具体实践后才能有更直观的理解。 参照: What are the issues with using Immutable.JS?.但不能否认Immutable.js很是符合react的思想,都在处理大规模数据时彰显优点。redux
Reselect:它用来替代咱们手写的state selector, 它的主要思想: state1 + state2 => state3, 缓存先决state,它们若是计算结果是相同的,就使用缓存结果不去改变最终state,一样也是immutable思想。 在结合immutable.js的时候,也是坑啊,仍是那个老问题,数据类型,state嵌套越深,越麻烦。 因此,如今明白为何强调Redux State扁平化了吧?axios
Redux Saga: Oh my.. 无比亲切,至于缘由: 我写过这么一篇文章:From Iterator To Async. Saga致力于解决复杂场景下的异步流程控制,用它来管理action触发,酸爽无比。 毕竟控制异步流程这种成就在JS话题下自己就是爽的不要不要的。 本质是使用generator,对于理解CO库的同窗们,掌握saga不在话下。在操做极其频繁的场景下(好比游戏),你会感觉到他的威力。 推荐一篇文章: Async operations using redux-saga, 在本项目里我主要用它来控制news数据的拉取,采用axios.
Styled Components: 老朋友,更新了2.0版本,一样配合styled-props,效果拔群。 至于一些宏观上的样式设置,的确不如直接写CSS那么直观。 我采用的方法是,特性按组件写,通性和一些涉及多层级样式都放在wrapper里。 也许单独使用styled-components并不能发挥出色,配合传统CSS写法,应该能够相得益彰。
ref: 对于ref的感受一直是又爱又恨,毕竟在react以前,dom操做被咱们玩的飞起,而react官方的态度一直是不建议使用。 在此次的项目中,markdown editor处的textarea我便采用了Uncontrolled的形式,使用ref保存dom引用。 初衷是为了对频繁的内容变更进行debounce处理,当编辑暂停时才触发一次内容state更新。 随着组件的增长,在一个嵌套达到3层的modal组件里,须要对textarea的value进行重置操做,好了,这下我得从父组件一层层的把这个ref传进去。 那感受简直不能再糟.... 一刹那感受官方文档就像和善的老司机,句句肺腑之言啊! 不过在你真的遇到这个坑前,是不会有多深的感觉的。 要解决这个恶心的传递,只有采用controlled形式,onChange监听,value直接连接state.
Perf: 做为性能测量的利器,测试结果让我发现styled-components的消耗是可观的,尤为是更新到v2.0版本后。在其余方面,因为本项目里的newsFeed可能会涉及频繁点击切换路径的状况,为了防止无谓的重复渲染,给全部presentational components都设置为PureComponent, 接着在一些只须要更新一次的组件里手写shouldComponentUpdate
, 仍是强调一点: 必须十分清楚传入的参数,以及其结构,并考虑这个结构是否在生产环境中有变化的可能致使判断失效。 还有个值得注意的问题是react-router-v4里的NavLink检测location渲染当前激活地址的link(activeClassName属性)时,注意组件是不是PureComponent, 若是是,必须在父组件传入location,不然PureComponent的shouldComponentUpdate
将会断定参数无变化,从而block掉link的动态渲染。参照: Dealing with Update Blocking
Server Side: 因为是使用leancloud部署,用node环境,为了解决v2ex api的跨域问题,本身写了一套请求转发,可是问题来了: 单页APP里为保证刷新后不出现cannot get等问题,必须写上一条app.get('*', (req, res) => {res.sendFile('index.html的路径')} )
, 这就很麻烦了,后来通过请教,用正则过滤了请求转发涉及的路径,就避免了路径全局拦截。可是! 这样刷新后,又会遇到cannot get的问题了。 由于再次刷新时url已经变化,浏览器会去请求这个地址,然后台并无提供此路径的响应。 最好的办法是使用nginx部署环境。(express难道就没办法? 仍是我服务端知识短浅啊...要恶补) 另一个问题: 生产环境和部署环境下因为使用了不一样的请求地址,返回的数据的结构存在微小差别,以本项目为例,请求v2ex topic在生产环境下数据是res.data
,而到了部署环境下因为使用了本身设置的请求地址,返回的数据成了res.data[0]
,找了好久才发现问题,值得注意。
Cancellation: 在newsfeed里频繁切换页面时还有一个问题: 也许下一个页面呈现时,上一个页面中触发的fetch操做还没执行完毕。举个例子: 我进入了v2ex的页面,此时组件拉取新闻信息,接着我几乎不等待便切换至github,此时对于v2ex的拉取还在进行。这就是一种浪费了。 为了解决它,起初我尝试用saga结合react-router-redux里提供的LOCATION_CHANGE
action来做为断定取消以前未完成fetch的标志。 测试发现就算我点击的是同一个link,依然会触发LOCATION_CHANGE
,(真坑啊,彻底不符合直觉好么!?)那么有这么一个场景: 当你进入hackerNews等待数据返回,因为时间较久,你不耐烦的再次点击了hackerNews的Link,Boom~~! LOCATION_CHANGE
dispatched. 因而乎你的fetch被取消了...,因此用LOCATION_CHANGE
做为断定标志在首次拉取这个场景下是不可行的(论corner case重要性..), 后来想出来的解决办法是在三块新闻组件的componentDidMount
的顶部dispatch一个STOP_FETCH
action,而后将断定取消的标志改成:STOP_FETCH
,算是解决了,可总感受有点暴力,由于一旦组件变多,将要手动。接下来将继续思考更优雅的解决方案,若是大神们有答案,请告知。
最大的收获: 主动找上问题,而不是问题找上你。 不折腾,不踩坑,进步颇微。
当container变多时,直接将container component做为单位,单独设立目录,而后放置对应的components/styled-components/reducer/action. 这就是按feature组织目录的方法。 细致的拆分,解耦性更好,以container component为单位进行修改时,大大下降误伤率的同时,隔离无关的信息。
大概总结出一个Learn by doing的心路历程:
被何尝试的技术吸引,而且有了下一个project的idea
尝试拆分所需技能,分红组块(裂墙推荐知乎金旭亮老师组块学习论)
漫长的学习过程: 读文档,找样例,写小demo倒腾API。因为组块积累未彻底,因此没法对project全面下手,天然会很烦躁,而且踏出了温馨区,接收更多的信息。
组块知识积累完毕,project开始施工: 从最简功能需求开始,不断增长新feature: problem -> google -> resolve.
Project成型,评估,修正,改进,more problem come in.
项目总结。而后享受一下独立完成project的成就感。同时也会深入理解本身的不足,为本身的技术精进之路指明了方向。
以project为单位,循环以上步骤。
最后的领悟: 我早几年干什么去了... 捶胸泪目ing。
将来可能会补上的:
白噪音组合播放
番茄钟
音乐部分(哈哈哈偷懒了时间很少了,赶忙找工做。)
做为一名新人,还请你们多多指教。一样无耻的求star,2333。