前言
书接上回初入职场一年半的前端练习生总结练习(工作)时长1年半的前端er年终终结。
笔者在发布上一篇博客的四个月内又有了很大的收获和成长,在此记录一下。
截至目前个人情况概览
~ o( ̄▽ ̄)ブAloha,这里是superlit帆,很开心如愿以偿得到团队的认可和支持有了管理更大的项目的权利,在此主要是复盘一下最近这四个月在工作中的成长和感悟,希望后续可以将这段时间的经历化作更好的成长的动力与养料,以下分项目管理、学习记录、整体复盘三个部分记录。
关键词:项目管理复盘、学习复盘、总结与期许
项目管理复盘
项目前期筹备
可以和自己的前辈(比如说上级)先探讨下管理这件事怎么做会更好,而不是被动等待或者下意识觉得对方会强制干预,实际上来说当管理权交接到自己手上的时候能强制干预的只有自己。有很多问题,比如说屏幕适配的最佳实践方式、请求的封装、数据的模拟等都是可以通过沟通交流往最佳实践上靠拢。
概念拉齐
什么样是可交付的,什么样是一个项目的完成态,我以为的是我以为的,但是验收人想要的才是真的需要的。本质上来说我只是乙方,早点弄清楚甲方真正的需求(也就是验收标准)对谁都好。
责任划分
模块与模块之间的边界在哪里,这个自己是需要清楚的。比方后续再带队做项目的话,我会更加强调模块与模块之间完成度的标准与责任划分,更严谨细致的要求自己和其他成员按时需要达到的交付成果。
更为尖锐的管理是有必要的
一是一二是二,需要其他成员做到的绝不让步,这一点在这次项管中受益匪浅。以后希望自己可以更加尖锐高效的做事,保持温和谦逊的做人。
多反问自己作为项管足够了解业务吗?
工作一年多之后发现前端工程师其实真的不能止步于前端,尤其是想要升管理的话,毋庸置疑你自己是需要对自己负责的项目业务逻辑十分清晰的,这就要求我们结合产品设计从使用者的角度出发去想如果我是使用者我希望这个服务于我的系统我会怎么做,以及我可能会怎么做。这样不管是在UI设计还是在交互实现以及后期的测试用例评审时你都能hold住项目并且提出自己对项目的建议与理解,即从开发者也从使用者的角度来说,这样的前端交互真的是好的吗?
总结
知识储备决定上限,但是对资源的利用能极大的拓展上限。
学会借力的话就会事半功倍的,有力可借我必借,比如更优的业务实现方法和更好的管理方式这些都是可以通过向行业内其他热心前辈请教习得的。
学习复盘
看比自己强的人的代码学到的东西
同样的功能为什么别人写出来的代码量是自己的一半?为什么他写的干净漂亮的同时又很简洁后期维护起来也很方便。
观察了下主要是以下几点:
1.逻辑十分的清晰,不耦合(这里注意避雷自己之前滥用useEffect监听变量的情况,比方用useEffect监听列表类请求条件的变更更好的方式是在条件变更时执行对应的搜索函数)
2.工具使用的很好,同样使用hook但是他用的hook就很干净利落,拳拳到肉;好,那么为什么他这样用呢?知其然也知其所以然,这样下次我可以用的比他更好
3.代码语义化做得很好,变量和方法取名都是合理且通俗易懂的
4.编写代码时考虑问题尽可能深入全面的考虑:代码需要有好的容错机制,要考虑代码后期的拓展性是否强
举个例子,条件对象中某个条件字段值变更时一个变量也要跟着变更的时候,不需要在单个变更的时候写变更操作,可以封装对应的条件变更函数,在变更函数执行的时候直接去做这个变更操作,就能达到一改全改的效果了。
以下列举下通过其他前辈的代码自主学习了解到的知识:
hook的正确使用
useEffect的滥用危害,以及到底怎么用合适
编写代码的时候之前会习惯用useEffect去监听表单请求变量去获取表单数据,就像这样:
tsx
function App() {
const [list, setList] = useState([]);
const [params, setParams] = useState(null);
//初始化获取数据和更新params后的回调写在一起
useEffect(() => {
fetchList(params).then(list => {
//...业务逻辑
setList(list);
})
}, [params]);
function onSubmit(opt) {
setParams(opt);
}
// ...
}
被前辈友情提醒后决定痛改前非深入去了解下这样用useEffect为什么不好。自己仔细思考推敲并且去查阅资料后发现这样的使用确实是有问题的: 首先提交表单 显然是个事件,事件的逻辑应该写在事件回调中,而不是useEffect
中。 很明显之前一直将Effect和Event混淆了,Event
的特点是:是由某些行为触发,而不是状态变化触发的逻辑 ,Effect
则与Event
相反,他是由某些状态变化触发的,而不是某些行为触发的逻辑,行为是行为,状态是状态,二者不是一个概念。 其次随着业务发展,后续代码里也有这样的情况发生:
tsx
useEffect(() => {
fetchList(options).then(list => {
// ...业务逻辑
// 更新data
setList(list);
})
}, [params, xxx, yyy, zzz]);
这样会导致后续维护时很难清楚fetchList
方法会在什么情况下执行,因为:
useEffect
的依赖项太多了- 很难完全掌握每个依赖项变化的时机
所以,在React
中,我们需要清楚的区分Event
与Effect
,也就是清楚的区分一段逻辑是由行为触发的,还是状态变化触发的?
那么正确的使用方式就是让他去到他该去的地方,在提交表单的事件回调函数里用变量去请求:
tsx
function App() {
const [list, setList] = useState([]);
const [params, setParams] = useState(null);
function onSubmit(opt) {
setParams(opt);
fetchData(params).then(list => {
//...业务逻辑
setList(list);
})
}
// ...
}
这里放下查资料的时候看到的来自卡颂大大的文章(感谢博主分享),顿时感觉醍醐灌顶: 一个新的React概念:Effect Event 上述内容为自主思考+看他的文章+回顾react官方文档的产出。
useMemo和useCallBack啥时候用比较好?
好嘛,明确的知道useEffect清楚是什么该怎么用之后,常用的useMemo、useCallBack咱也合理的用起来。
cr的时候前辈有特意提醒useMemo不能滥用,不需要每个组件都包一层useMemo,滥用反而会弄巧成拙,那么我们再回过头来了解下,滥用可能会造成什么样的危害:
- 缓存是有成本的,小的成本可能会累加过高。
- 默认缓存无法保证足够的正确性。
useMemo/useCallback 最佳实践为:
-
大部分的 useMemo 和 useCallback 都应该移除,他们可能没有带来任何性能上的优化,反而增加了程序首次渲染的负担,并增加程序的复杂性。
-
使用 useMemo 和 useCallback 优化子组件 re-render 时,必须同时满足以下条件才有效。
- 子组件已通过 React.memo 或 useMemo 被缓存
- 子组件所有的 prop 都被缓存
-
不推荐默认给所有组件都使用缓存,大量组件初始化时被缓存,可能导致过多的内存消耗,并影响程序初始化渲染的速度。
参考文档:React 文档 useMemo 这里强强强烈推荐我的另一篇参考文档,上述思考来源于自身实践+博主tumars的总结:如何正确使用 useMemo 和 useCallback
状态管理工具------dva中的model学习与使用
这次项目里有用到基于redux理念设计的dva里的model去管理数据流(相较于之前纯state和context管理状态或者mobx管理状态这次使用是全新的家伙)。
那么状态管理工具dva解决了什么问题,他的最佳实践应该是什么样的呢?
状态管理工具的作用,就是状态的共享,当共享状态发生变化,所有使用方都会触发重新渲染。所以,当然是状态需要被多方共享的时候,才需要使用状态管理工具。按这个概念倒推一下,纯粹的组件里其实是不应该出现共享的状态的,而简单的,诸如单点触发类的弹窗打开关闭的状态也不需要放到这里。
不过使用的时候个人感觉最明显的一个是这和我之前写vue用的vuex手感很像,其次就是dva model对ts的支持并不友好。 这里放一下dva官网链接:dva官方文档
和我觉得归纳的很好的来自博主肥康的不同状态管理工具对比的博客链接: React 状态管理器,我是这样选的
博主已体验过mobx与dva,下次想试试vue中的piana(马住,体验备选预备役)。
正确使用React中的key能极大的提升渲染性能
好了问题来了,到底为啥能极大提升性能?比起笼统的我知道他可以,我更想知道究竟为什么能极大的提升性能,于是又开始了查资料之旅,查阅到:
只有在重渲染时为了和相邻的同类型元素(即扁平列表)区分时,才需要 key 属性(这一点很重要!)。
重渲染过程的简化算法如下:
首先,React 将生成元素 「之前」和 「之后」的 快照。
其次,React 将尝试识别页面中已经存在的元素,以便重新使用它们,而不是从头开始创建。
- 如果 key 属性存在,它将假定重渲染 「之前」和「之后」key 相同的项是相同的。
- 如果 key 属性不存在,它将使用索引作为默认 key。
第三,它会:
- 删除在重渲染「之前」存在但「之后」不存在的项目------即卸载(unmount)它们。
- 从头开始创建在「之前」阶段不存在的项目------即加载(mount)它们。
- 更新 「之前」存在并在 「之后」继续存在的项目------即重新渲染(rerender)它们 。
重要启示:
- 切勿在 key 属性中使用随机值:这将导致项目在每次渲染时重新挂载。当然,除非这就是您的意图。
- 在「静态」列表(即那些项的数量和顺序保持不变的列表)中使用数组的索引作为 key 是没有坏处的。
- 当列表可以重新排序或者可以在随机位置添加条目时,使用条目唯一标识符(id)作为 key
- 对于无状态项的动态列表(例如分页列表,搜索和自动完成结果等),可以使用数组的索引作为 key,在这些列表中,项会被新的项替换(而非卸载后再创建)。这将提高列表的性能。
总结与期许
在今后的职业生涯里还有很多带大大小小的项目的机会,如何把一个项目做得更好的同时让项目组内的每一名成员都感到有所收获是需要不断去思考的课题。
这段时间收获真的很丰富,最大的感受是你的认知上限决定了你做出来的事情的认知上限,不想十年如一日的原地踏步就去不断的去质疑自己能不能做得更好能不能更高效,有计划的朝这个方向努力才会真的做得更好,而好的借力又可以让自己事半功倍的去完成好负责的事情。
感谢这次一起合作的小伙伴,尤其是愿意让我放手去做的前辈们的支持。
可以学习的还有很多,未来还有很长很远的路可以走,我期待带着这段时间的收获,下一次能写出更好(逻辑严谨、可靠、简洁)的代码,交付出更漂亮的项目。