极客时间-笔记:React Hooks 核心原理与实战

认识react

  1. JSX 并不是一个新的模板语言,而可以认为是一个语法糖。
  2. React.createElement 作用就是创建一个组件的实例;参数:
  • 第一个参数表示组件的类型;
  • 第二个参数是传给组件的属性,也就是 props
  • 第三个以及后续所有的参数则是子组件。
React.createElement(
 "div",
 null,
 React.createElement(
   "button",
   { onClick: function onClick() {
       return setCount(count + 1);
     } },
   React.createElement(CountLabel, { count: count })
 )
);

理解hooks

  1. hooks的好处:简化了逻辑复用。

如果用class组件实现逻辑复用需要封装高阶组件;有以下缺点:

  1. 代码难理解,不直观,很多人甚至宁愿重复代码,也不愿用高阶组件;
  2. 会增加很多额外的组件节点。每一个高阶组件都会多一层节点,这就会给调试带来很大的负担。
  1. 在 Class 组件中,代码是从技术角度组织在一起的,例如在 componentDidMount 中都去做一些初始化的事情。而在函数组件中,代码是从业务角度组织在一起的,相关代码能够出现在集中的地方,从而更容易理解和维护。

内置 Hooks

  1. React 提供的 Hooks 其实非常少,一共只有 10 个,比如 useState、useEffect、useCallback、useMemo、useRef、useContext 等等。
  2. 副作用是指一段和当前执行结果无关的代码。
  3. useEffect 让我们能够在下面四种时机去执行一个回调函数产生副作用:
  • 每次 render 后执行:不提供第二个依赖项参数。比如useEffect(() => {})。
  • 仅第一次 render 后执行:提供一个空数组作为依赖项。比如useEffect(() => {}, [])。
  • 第一次以及依赖项发生变化后执行:提供依赖项数组。比如useEffect(() => {}, [deps])。
  • 组件 unmount 后执行:返回一个回调函数。比如useEffect() => { return () => {} }, [])。
  1. Hooks 的使用规则包括以下两个:
  • 只能在函数组件的顶级作用域使用;
  • 只能在函数组件或者其他 Hooks 中使用。
  1. useCallback解决事件处理函数的问题:
  • 不仅增加了系统的开销
  • 每次创建新函数的方式会让接收事件处理函数的组件,需要重新渲染。
  1. useCallback和useMemo做了同一件事情:建立了一个绑定某个结果到依赖数据的关系。只有当依赖变了,这个结果才需要被重新得到

用useMemo实现useCallback:
const myEventHandler = useMemo(() => {
// 返回一个函数作为缓存结果
return () => {
// 在这里进行事件处理
}
}, [dep1, dep2]);

问题:useCallback/useMemo 什么情况下使用?是所有情况?还是个别情况,例如计算量较大等情况?

  1. useRef:
  • 在多次渲染之间共享数据

使用 useRef 保存的数据一般是和 UI 的渲染无关的,因此当 ref 的值发生变化时,是不会触发组件的重新渲染的,这也是 useRef 区别于 useState 的地方。

  • 保存某个 DOM 节点的引用

function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => {
// current 属性指向了真实的 input 这个 DOM 节点,从而可以调用 focus 方法
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
ref 这个属性提供了获得 DOM 节点的能力,并利用 useRef 保存了这个节点的应用。这样的话,一旦 input 节点被渲染到界面上,那我们通过 inputEl.current 就能访问到真实的 DOM 节点的实例了。

  1. useContext 定义全局状态

和全局的变量去保存数据的区别?
就是为了能够进行数据的绑定。当这个 Context 的数据发生变化时,使用这个数据的组件就能够自动刷新。但如果没有 Context,而是使用一个简单的全局变量,就很难去实现了。

  1. useContext 的缺点:
  • 会让调试变得困难,因为你很难跟踪某个 Context 的变化究竟是如何产生的。
  • 让组件的复用变得困难,因为一个组件如果使用了某个 Context,它就必须确保被用到的地方一定有这个 Context 的 Provider 在其父组件的路径上。

所以在 React 的开发中,除了像 Theme、Language 等一目了然的需要全局设置的变量外,我们很少会使用 Context 来做太多数据的共享。需要再三强调的是,Context 更多的是提供了一个强大的机制,让 React 应用具备定义全局的响应式数据的能力。

自定义hooks的使用场景

  • 抽取业务逻辑;
  • 封装通用逻辑;
  • 监听浏览器状态;
  • 拆分复杂组件。

全局状态管理:如何在函数组件中使用 Redux?

  1. 理解 Redux 的三个基本概念:State、Action 和 Reducer。
  • 其中 State 即 Store,一般就是一个纯 JavaScript Object。
  • Action 也是一个 Object,用于描述发生的动作。
  • 而 Reducer 则是一个函数,接收 Action 和 State 并作为参数,通过计算得到新的 Store。

好处:1. 可预测性(Predictable):即给定一个初始状态和一系列的 Action,一定能得到一致的结果,同时这也让代码更容易测试。2. 易于调试:可以跟踪 Store 中数据的变化,甚至暂停和回放。因为每次 Action 产生的变化都会产生新的对象,而我们可以缓存这些对象用于调试。Redux 的基于浏览器插件的开发工具就是基于这个机制,非常有利于调试。

  1. React 和 Redux 共同使用时的单向数据流:
  2. 什么是异步action?Middleware 在 Action 真正到达 Reducer 之前提供的一个额外处理 Action 的机会:

Redux 中的 Action 不仅仅可以是一个 Object,它可以是任何东西,也可以是一个函数。利用这个机制,Redux 提供了 redux-thunk 这样一个中间件,它如果发现接受到的 action 是一个函数,那么就不会传递给 Reducer,而是执行这个函数,并把 dispatch 作为参数传给这个函数,从而在这个函数中你可以自由决定何时,如何发送 Action。

复杂状态处理:如何保证状态一致性?

  • 一个是状态最小化原则,也就是说要避免冗余的状态;
  • 另一个则是唯一数据源原则,避免中间状态。

函数组件设计模式:如何应对复杂条件渲染场景?

  1. 容器模式:实现按条件执行 Hooks
  • 把条件判断的结果放到两个组件之中,确保真正 render UI 的组件收到的所有属性都是有值的。
  • 还有一种做法,就是把判断条件放到 Hooks 中去。
  1. 使用 render props 模式重用 UI 逻辑


    逻辑复用,自定义hook亦可

事件处理:如何创建自定义事件?

  1. React 原生事件的原理:合成事件(Synthetic Events)

由于虚拟 DOM 的存在,在 React 中即使绑定一个事件到原生的 DOM 节点,事件也并不是绑定在对应的节点上,而是所有的事件都是绑定在根节点上。然后由 React 统一监听和管理,获取事件后再分发到具体的虚拟 DOM 节点上。
在 React 17 之前,所有的事件都是绑定在 document 上的,而从 React 17 开始,所有的事件都绑定在整个 App 上的根节点上,这主要是为了以后页面上可能存在多版本 React 的考虑。

  1. React 这么做的原因主要有两个:
  • 虚拟 DOM render 的时候, DOM 很可能还没有真实地 render 到页面上,所以无法绑定事件。
  • React 可以屏蔽底层事件的细节,避免浏览器的兼容性问题。同时呢,对于 React Native 这种不是通过浏览器 render 的运行时,也能提供一致的 API。
  1. 由于浏览器事件的冒泡模型。无论事件在哪个节点被触发, React 都可以通过事件的 srcElement这个属性,知道它是从哪个节点开始发出的,这样 React 就可以收集管理所有的事件,然后再以一致的 API 暴露出来。
  2. 虽然自定义事件和原生事件看上去类似,但是两者的机制是完全不一样的:
  • 原生事件是浏览器的机制;
  • 而自定义事件则是纯粹的组件自己的行为,本质是一种回调函数机制。

路由管理:为什么每一个前端应用都需要使用路由机制?

  1. React Router 管理


    react router示例

这里需要注意,React Router 不仅支持浏览器,还支持 React Native,以及一些用 Web 实现的移动 App,所以它提供了多个 npm 模块。

  1. BrowserRouter、Link、Route、Switch 等组件的用法及作用。
  • BrowserRouter:表示用标准的 URL 路径去管理路由,比如 /my-page1 这样的标准 URL 路径。除此之外,还有 MemoryRouter,表示通过内存管理路由;HashRouter,标识通过 hash 管理路由。我们自己实现的例子其实就是用的 hash 来实现路由。
  • Link:定义一个导航链接,点击时可以无刷新地改变页面 URL,从而实现 React Router 控制的导航。
  • Route: 定义一条路由规则,可以指定匹配的路径、要渲染的内容等等。
  • Switch:在默认情况下,所有匹配的 Route 节点都会被展示,但是 Switch 标记可以保证只有第一个匹配到的路由才会被渲染。
  1. 使用嵌套路由:实现二级导航页面所谓嵌套路由,也称为子路由,就是一个页面组件内部,还需要通过 URL 上的信息来决定组件内部某个区域该如何显示。
    嵌套路由示例
  2. 在 URL 中保存页面状态

一方面可以提升用户体验,另一方面也可以简化页面之间的交互

  1. 路由层面实现权限控制

我们完全可以利用前端路由的动态特性。你已经看到了,路由是通过 JSX 以声明式的方式去定义的,这就意味着路由的定义规则是可以根据条件进行变化的,也就是所谓的动态路由。

jsx声明routes

按需加载:如何提升应用打开速度?

  1. 如何实现按需加载?

使用 import 语句,定义按需加载的起始模块语法是 import(someModule)。

webpack分包

react-loadable按需加载

  1. 使用 service worker 缓存前端资源
  • 缓存永远不过期。你只要下载过一次,就永远不需要再重新下载,除非主动删除。
  • 永远不会访问过期的资源。换句话说,如果发布了一个新版本,那么你可以通过版本化的一些机制,来确保用户访问到的一定是最新的资源。

1.注册 Service Worker


注册service worker
  1. 在 Service Worker 安装之后初始化缓存机制


    安装
  2. 拦截请求
    拦截请求

    参考链接:cache mdn
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容