现在的前端招聘JD里大概率会有一条要求,“Vue,React 有其一经验”,引申的意思可能是:一个成熟且有着现代前端开发经验的开发者,要学会一门框架应该是成本很低的事情。人常说,框架都是相通的,是否如此呢?
确实,随着各家不停探索,框架的基本形态和功能设计日趋完善,最根本差异点最终演变成了框架开发者各自的理念差异,不同的理念让框架有了各自的设计模式和最佳实践,如果你要准备从现在开始学习掌握 React ,那么先理解 React 的设计理念至关重要。
这是一份适合有着前端开发经验,并习惯使用现代前端框架,却还没深入使用过 React 的老鸟快速入门指南,如果你还没有接触过前端框架,那建议直接在官方文档仔细从头看起。
当我们决定要正式去学习,那我们起码要以掌握它为基本目标,一个有经验的开发者,看一篇技术文档,写一个 Hello world 轻而易举,你即使没仔细了解过 React 的设计理念,翻翻文档应该也能把简单的功能写出来。
但是,这不叫掌握,顶多叫能用,掌握是指你要在了解过所有功能之后,理解框架设计者的设计理念和最佳实践,并最好懂得其实现的基本原理,就基本算是掌握了。
本文我会简单说说我理解的 React 设计理念、常识、和一些最佳实践,有些地方对照 Vue 会更容易理解,帮助你快速了解 React。文章略长,请耐心阅读。
React核心原理就是:当数据发生变化时,UI随之更新,就是所谓的数据驱动,之所以说 React 很有野心,是因为它完全抛弃了前端熟悉的开发模式,创造出一个全新的思路,试图颠覆前端工作者的开发方式,确实这是个很伟大的尝试。
当然你说 Vue 同样是数据驱动,但不同的是 Vue 做了更上层的封装,Vue 设计了新的类似 HTML 的模板语法,通过选项属性为开发者提供编写逻辑和 state 的地方,再通过一个 viewModel,当监听到 state 变化时再去更新 view ,总结起来就是在前端现有开发习惯下,以“糖水”的方式“注入”了更多让开发变的更加容易的功能,但无疑设计上会变的非常的复杂。
而 React 选择了完全不同的一条路,React 选择让前端开发回归语言本身,从 js 自身找到解决方案,一次性解决以下的所有问题:
最终 React 选择了 js 中的 【函数】 去承载所有的功能,所以 React 的函数组件本质上真的就只是 js 中的普通函数而已,而非 .vue 这种专门需要复杂编译的新产物,一定要理解它就是一个普通函数。
那一个简单的函数是如何实现上述这么多复杂的功能的呢:
但这正是 React 对开发方式的一种颠覆,让开发者抹平传统开发中 HTML 与 JS 之间巨大的割裂感,更专注于 js 逻辑。
export default function({foo}){
const dom = <div>React dom 1</div>
const dom = <div>React dom 2</div>
if(foo){
return dom1
}else{
return dom2
}
}
import { useState } from 'react'
export default function(){
// 当函数组件中逻辑更新data时,当前函数组件会重新执行,生成最新的dom区更新视图
const [data, setData] = useState(1)
return <div>{data}</div>
}
至此,React 几乎全部的核心功能就都通过一个简单函数实现了,所谓函数组件,几乎完全遵循 js 函数的特性,对于开发者来说几乎没有新的概念引入,这相比于 Vue 极大的降低的心智负担,谁不喜欢简洁而纯粹的东西呢。
没有模板、没有生命周期、没有指令、没有各种各样的语法糖、没有复杂的执行过程,这是一个只有函数的世界,太优雅了!
写 Vue 时你可能会觉得以后可能随时会出个新功能,让开发变的更舒适,写 React 你会觉得,这就到头了,弟弟!
这玩意谁研究的呢你说,不得不说是个人才!
再聊一个广大网友最津津乐道的问题,所以 React 与 Vue 到底谁更好呢?
为了你更容易理解 React 的各种概念,在此我们先梳理下 React 重要的历史版本。
从 V16.8.0 开始,React 引入了 hooks 的概念,可以算是 React 里程碑式的更新,hooks 的引入弥补了之前函数组件的缺陷,函数组件因此大放异彩。
从此时开始 React 真正同时并存两种截然不同的开发方式,Class 组件与函数式组件,在22年最新 V18 新版的官方文档更新之前,React 还一直默认使用 Class 组件讲解 React ,所以你可能会因为选择哪种组件而觉得困惑。
Class 组件和函数组件到底该用哪个?
回答:只需要用函数组件,class组件已经成为历史,可以完全抛弃了
已经写好 Class 组件需不需要改?
回答:不需要
能不能在老项目里写函数组件?
回答:可以,Class组件与函数组件完全可以共存,只要注意 React 版本就可以
React 组件演变顺序经过三个阶段:
在上面讲理念的段落,已经讲过,函数才是贯彻 React 思想最好的载体,所以函数作为组件是最符合的,可是在当时有个局限就是,函数组件内部无法留存状态,函数也更没办法设计一套生命周期,用函数作为组件有严重缺功能陷的,所以在当时选用 Class 作为组件的载体。
Class 组件我现在看起来依然觉得很难接受,原因有几点:
可以说 Class 只是为了实现组件基本功能而用,所以最初看到 React Class 组件时,反而觉得没有 .vue 单文件组件来的优雅和直接。
但这一切问题都随着 hooks 的推出迎刃而解,彻底抛弃生命周期,并通过 hooks 引入一个不受函数组件重复执行影响的外部变量作为函数组件内的状态,当这个状态变更时,函数组件随之重新渲染,将最新的状态渲染到页面。
现在时间来到了2023年,函数组件 + Hooks 的开发方式广受好评,你已经没有任何理由再去使用 Class 组件了
顺着上面说函数组件早期有很大的不足,就是不能留存状态与很难设计生命周期,那 Hooks 是如何解决的呢。
想象一下如果将一个纯函数作为组件,纯函数通过自身的重复执行来做到渲染与重复更新,需要在函数多次执行期间保存其中的状态,那我们肯定是需要这个函数之外的空间来存储状态,并且当这个状态被改变时,能监听到并触发函数组件的重新渲染。
Hooks 就是这种方式,字面意思就是钩子,Hooks 将函数钩到一个可能会变化的数据源上,当这个数据变化时,被钩在上面的函数会重新执行,生成新的结果。
useState 用法很简单,如下代码,引入后会在当前函数外声明一个变量:
最终复杂的视图渲染就在函数组件一遍又一遍简单的重复执行中完成了。
而且 Hooks 虽然是将状态声明在函数外部,但写法上仍然是写在函数组件的内部的,这让人写起来并不会有函数组件的割裂感
import { useState } from 'react'
export default function(){
// 当函数组件中逻辑更新data时,当前函数组件会重新执行,生成最新的dom区更新视图
const [data, setData] = useState(1)
return <div>{data}</div>
}
const [state1, setState1] = useState(1)
useEffect(()=>{
//只有state1发生变化时才执行这段副作用代码
}, [state1])
useEffect(()=>{
//只有state1发生变化时才执行这段副作用代码
document.addEventListener('click', fn);
return ()=>{
document.removeEventListener('click', fn);
}
}, [])
最后还缺少一个非常重要的功能,就是在函数重复执行渲染过程中的数据共享,我们需要一个能从纯函数重复执行中逃脱,贯穿整个组件渲染的变量,有人说,useState 不就是做这个的吗?但是 state 是和渲染绑定的特殊状态,有以下绑定的特性:
export default function () {
const [count, setCount] = useState(0);
function click(){
setCount(2);
console.log(count) // 打印 0
}
return <>
<span onClick={click}>点击</span>
<p>{count}</p>
</>
}
所以需要在一个复杂的时机才能拿到 state 最新的值,而我们需要一个与渲染无关的数据,能贯穿重复的函数执行,变更后不需要触发函数重新渲染,并且不需要在意此时函数的渲染过程是非常有必要的
useRef 就实现了这个功能,他在函数组件首次执行时创建,你可以在函数任何逻辑中直接更改 useRef 的值,它会立即同步更改,并贯穿重复的函数执行,无需任何心理负担。
除了能存储函数组件重复执行过程的共享数据,useRef 在存储DOM节点,和清理某次渲染过程产生的闭包逻辑有非常重要的意义
import { useState, useRef } from "react";
export default function Timer() {
const [time, setTime] = useState(1)
const timer = useRef(null);
const domRef = useRef(null);
const click = function(){
// 需要再每次执行前清理掉之前的定时器,
// 如果不使用 useRef ,函数组件重复渲染后无法找到上一次函数执行产生的定时器对象
window.clearInterval(timer.current);
// 延时器对象赋值给 useRef
timer.current = window.setTimeout(() => {
setTime(time + 1);
}, 5000);
}
const getDOm = function(){
// 我们可以毫无负担的获取到domRef节点,不受函数组件重复执行的影响
console.log(domRef)
}
return (
<div ref={domRef}>
<p>{time}</p>
<button onClick={click}>add</button>
<button onClick={getDOm}>getDom</button>
</div>
);
}
理解了函数组件极其简洁的设计理念,再加上三个十分简单的 Hooks,那我们是不是已经可以自如的开发 React 代码了呢?
我的答案是,是的
虽然 React 到现在已经推出了十几个 Hooks,但是正常的开发过程中 useState useEffect useRef 几乎可以解决所有问题,我认为除了这三个之外其他所有的 Hooks 都只是为了优化而存在,无论你用与不用,都不影响组件的开发
除了这三个核心 Hooks 以外,还需要提一提的也就是三个用来优化组件的 Hooks :useCallback、useMemo、useContext
import { useState, useRef } from "react";
export default function ({a,b}) {
// 函数内部计算,每次函数重新渲染都会重新计算,无论 a b 是否变化
// 如果这里是非常占耗CPU的计算,可能会阻塞页面渲染
const c = a + b
// 每次函数重新渲染方法都会重新声明
const click = function(){
// 声明一个内部方法
}
return (
<div>
<p>{c}</p>
<button onClick={click}>click</button>
</div>
);
}
全文说了这么多,其中强调的最重要一条就是开发思维的转换,思维不转换你永远无法灵活的去使用,这里要重点提到 React 带来的另外一个给我们开发方式带来巨大的转变的特性:自定义 Hooks。
在以前无论是 Vue 还是 React 组件内的逻辑复用都异常艰难,通常情况我们只能封装 js 自身的对象和方法,比如封装一个函数,但组件内部的功能却是无法封装的,比如我们只能封装一个普通方法,不可能封装出一个带有响应式的方法。
这个过程中 React 出现过一些组件内逻辑封装的设计模式,比如高阶组件HOC、混入Mixin,Vue 也曾采用过 Mixin ,但使用度很低现在也都被官方废弃了,因为他们的使用实在太过牵强,很多人宁愿复制代码,也不想使用他们,我就是其中一员。所以我们需要一个能将组件内逻辑再次封装复用的功能,自定义Hooks的推出就是解决了这一点。
比如我们要在多个组件中实现获取视口宽度的功能,在以前如果我们不想在每个组件中都写一套事件监听程序,那就需要在父组件中写一个监听程序,监听到变化后将视口宽度通过 props 传递给子组件,子组件才能响应式更新,而现在我们可以在自定义 Hooks 直接使用 useState 给组件返回一个响应式的 state。
// useWindowSize.js
export default function useWindowSize (){
const [size, setSize] = useState(getSize());
useEffect(() => {
const handler = () => {
setSize(window.innerWidth)
};
window.addEventListener('resize', handler);
return () => {
window.removeEventListener('resize', handler);
};
}, []);
return [size];
};
// jsx中使用
export default function(){
const [size] = useWindowSize();
if (size >1000 ) {
return <SmallComponent />;
}else{
return <LargeComponent />;
}
};
从此在 React 中,又多了一种新的封装形态,自定义 Hooks,让相同业务逻辑拆分的更清晰,降低代码的冗余,提高代码的复用程度
在函数式编程中,函数是头等对象即头等函数,这意味着一个函数,既可以作为其它函数的输入参数值,也可以从函数中返回值,被修改或者被分配给一个变量。λ演算是这种范型最重要的基础,λ演算的函数可以接受函数作为输入参数和输出返回值。
比起指令式编程,函数式编程更加强调程序执行的结果而非执行的过程,倡导利用若干简单的执行单元让计算结果不断渐进,逐层推导复杂的运算,而不是设计一个复杂的执行过程。(来自维基百科)
文章的最后我想探讨下我对React 设计的理解。
很多人在从 Vue 转 React 觉得不太适应,或者从 Class 组件换成函数式组件觉得无法 get 到函数式组件设计的意义,我想这可能和编程习惯有关,传统前端开发方式我们受面向对象的编程思想影响颇深,我们常习惯在 类->继承->对象 的基础上去思考我们的开发方式,我们继承一个类,执行一个方法,改变一个属性,更新一个视图,我们在对象这个基础上,可以构建出很多复杂的功能。
但是 React 似乎更愿意在函数上做文章,React 用函数作为组件的基础,用纯函数简单的重复执行来替代复杂的视图更新流程,Hooks 也为是函数,useState 触发函数组件的执行并作为纯函数执行的不同输入,useEffect 将函数组件中所有的副作用从函数中隔离出去,自定义 Hooks 也是函数可无缝的和函数组件组合使用,所以如果你真的理解 【函数】 在 React 中的意义,那你就能体会到,React 看起来如此复杂的框架,归根结底只是通过函数的执行去渲染出一个视图而已,就是如此的简洁。
所以如果你能用函数式编程的思想去思考如何通过函数的执行实现你想要的功能,我想你才真正的掌握了 React 的精髓。
本文由微信公众号奇舞精选原创,哈喽比特收录。
文章来源:https://mp.weixin.qq.com/s/6QTdeM2l1htofCnKLZS6yw
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。