React Hooks 深入系列 —— 设计模式
本文是 React Hooks 深入系列的后续。此篇详细介绍了 Hooks 相对 class 的优势所在, 并介绍了相关 api 的设计思想, 同时对 Hooks 如何对齐 class 的生命周期钩子作了阐述。
React Logo 与 Hooks
React 的 logo 是一个原子图案, 原子组成了物质的表现。类似的, React 就像原子般构成了页面的表现; 而 Hooks 就如夸克, 其更接近 React 本质的样子, 但是直到 4 年后的今天才被真正设计出来。 —— Dan in React Conf(2018)
why Hooks?
一: 多个组件间逻辑复用
: 在 Class 中使用 React 不能将带有 state 的逻辑给单独抽离成 function, 其只能通过嵌套组件的方式来解决多个组件间逻辑复用的问题, 基于嵌套组件的思想存在 HOC 与 render props
两种设计模式。但是这两种设计模式是否存在缺陷呢?
- 嵌套地狱, 当嵌套层级过多后, 数据源的追溯会变得十分困难, 导致定位 bug 不容易; (hoc、render props)
- 性能, 需要额外的组件实例存在额外的开销; (hoc、render props)
- 命名重复性, 在一个组件中同时使用多个 hoc, 不排除这些 hoc 里的方法存在命名冲突的问题; (hoc)
二: 单个组件中的逻辑复用
: Class 中的生命周期 componentDidMount
、componentDidUpdate
甚至 componentWillUnMount
中的大多数逻辑基本是类似的, 必须拆散在不同生命周期中维护相同的逻辑对使用者是不友好的, 这样也造成了组件的代码量增加。
三: Class 的其它一些问题: 在 React 使用 Class 需要书写大量样板, 用户通常会对 Class 中 Constructor 的 bind 以及 this 的使用感到困惑; 当结合 class 与 TypeScript 一起使用时, 需要对 defaultValue 做额外声明处理; 此外 React Team 表示 Class 在机器编译优化方面也不是很理想。
useState 返回的值为什么是数组而非对象?
原因是数组的解构比对象更加方便, 可以观察以下两种数据结构解构的差异。
返回数组时, 可以直接解构成任意名字。
[name, setName] = useState('路飞')
[age, setAge] = useState(12)
返回对象时, 却需要多一层的命名。
{value: name, setValue: setName} = useState('路飞')
{value: name, setValue: setName} = useState(12)
Hooks 传递的设计
Hooks 是否可以设计成在组件中通过函数传参来使用? 比如进行如下调用?
const SomeContext = require('./SomeContext)
function Example({ someProp }, hooks) {
const contextValue = hooks.useContext(SomeContext)
return <div>{someProp}{contextValue}</div>
}
使用传递的劣势是会出现冗余的传递。(可以联想 context 解决了什么)
Hooks 与 Class 中调用 setState 有不同的表现差异么?
Hooks 中的 setState 与 Class 中最大区别在于 Hooks 不会对多次 setState 进行合并操作。如果要执行合并操作, 可执行如下操作:
setState(prevState => {
return { ...prevState, ...updateValues }
})
此外可以对 class 与 Hooks 之间 setState
是异步还是同步的表现进行对比, 可以先对以下 4 种情形 render 输出的个数进行观察分析:
是否能使用 React Hooks 替代 Redux
在 React 16.8 版本之后, 针对不是特别复杂
的业务场景, 可以使用 React 提供的 useContext
、useReducer
实现自定义简化版的 redux, 可见 todoList 中的运用。核心代码如下:
import React, { createContext, useContext, useReducer } from "react"
// 创建 StoreContext
const StoreContext = createContext()
// 构建 Provider 容器层
export const StoreProvider = ({reducer, initialState, children}) => {
return (
<StoreContext.Provider value={useReducer(reducer, initialState)}>
{children}
</StoreContext.Provider>
)
}
// 在子组件中调用 useStoreContext, 从而取得 Provider 中的 value
export const useStoreContext = () => useContext(StoreContext)
但是针对特别复杂的场景目前不建议使用此模式, 因为 context 的机制会有性能问题。具体原因可见 react-redux v7 回退到订阅的原因
Hooks 中如何获取先前的 props 以及 state
React 官方在未来很可能会提供一个 usePrevious
的 hooks 来获取之前的 props 以及 state。
usePrevious
的核心思想是用 ref 来存储先前的值。
function usePrevous(value) {
const ref = useRef()
useEffect(() => {
ref.current = value
})
return ref.current
}
Hooks 中如何调用实例上的方法
在 Hooks 中使用 useRef() 等价于在 Class 中使用 this.something。
/* in a function */
const X = useRef()
X.current // can read or write
/* in a Class */
this.X // can read or write
Hooks 中 getDerivedStateFromProps 的替代方案
在 React 暗器百解 中提到了 getDerivedStateFromProps
是一种反模式, 但是极少数情况还是用得到该钩子, Hooks 没有该 api, 那其如何达到 getDerivedStateFromProps 的效果呢?
function ScrollView({row}) {
const [isScrollingDown, setISScrollingDown] = setState(false)
const [prevRow, setPrevRow] = setState(null)
// 核心是创建一个 prevRow state 与父组件传进来的 row 进行比较
if (row !== prevRow) {
setISScrollingDown(prevRow !== null && row > prevRow)
setPrevRow(row)
}
return `Scrolling down ${isScrollingDown}`
}
Hooks 中 forceUpdate 的替代方案
可以使用 useReducer
来 hack forceUpdate
, 但是尽量避免 forceUpdate 的使用。
const [ignored, forceUpdate] = useReduce(x => x + 1, 0)
function handleClick() {
forceUpdate()
}
Hooks 中 shouldComponentUpdate 的替代方案
在 Hooks 中可以使用 useMemo
来作为 shouldComponentUpdate
的替代方案, 但 useMemo
只对 props 进行浅比较。
React.useMemo((props) => {
// your component
})
useMemo 与 useCallback 的区别
useMemo(() => <component />) 等价于 useCallback(<component />)
- useCallback: 一般用于缓存函数
- useMemo: 一般用于缓存组件
依赖列表中移除函数是否是安全的?
通常来说依赖列表中移除函数是不安全的。观察如下 demo
const { useState, useEffect } = React
function Example({ someProp }) {
function doSomething() {
console.log(someProp) // 这里只输出 1, 点击按钮的 2 并没有输出。
}
useEffect(
() => {
doSomething()
},
[] //
React Hooks 深入系列 —— 设计模式的更多相关文章
- React Hooks 深入系列
本文基于近段时间对 hooks 碎片化的理解作一次简单梳理, 个人博客.同时欢迎关注基于 hooks 构建的 UI 组件库 -- snake-design. 在 class 已经融入 React 生态 ...
- [React Hooks长文总结系列一]初出茅庐,状态与副作用
写在开头 React Hooks在我的上一个项目中得到了充分的使用,对于这个项目来说,我们跳过传统的类组件直接过渡到函数组件,确实是一个不小的挑战.在项目开发过程中也发现项目中的其他小伙伴(包括我自己 ...
- react新特性 react hooks
本文介绍的是react新特性react hooks,本文面向的是有一定react开发经验的小伙伴,如果你对react还不是很熟悉的话我建议你先学习react并多多联系. 首先我们都知道react有3种 ...
- 30分钟精通React今年最劲爆的新特性——React Hooks
你还在为该使用无状态组件(Function)还是有状态组件(Class)而烦恼吗? --拥有了hooks,你再也不需要写Class了,你的所有组件都将是Function. 你还在为搞不清使用哪个生命周 ...
- 通过 React Hooks 声明式地使用 setInterval
本文由云+社区发表 作者:Dan Abramov 接触 React Hooks 一定时间的你,也许会碰到一个神奇的问题: setInterval 用起来没你想的简单. Ryan Florence 在他 ...
- 初探React Hooks & SSR改造
Hooks React v16.8 发布了 Hooks,其主要是解决跨组件.组件复用的状态管理问题. 在 class 中组件的状态封装在对象中,然后通过单向数据流来组织组件间的状态交互.这种模式下,跨 ...
- React hooks实践
前言 最近要对旧的项目进行重构,统一使用全新的react技术栈.同时,我们也决定尝试使用React hooks来进行开发,但是,由于React hooks崇尚的是使用(也只能使用)function c ...
- 理解 React Hooks
欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由志航发表于云+社区专栏 TL;DR 一句话总结 React Hooks 就是在 react 函数组件中,也可以使用类组件(classe ...
- React Hooks新特性学习随笔
React Hooks 是 React 16.8 的新增特性.它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性. 前言 本篇主要以讲几个常用的api为主. 1.u ...
随机推荐
- IM即时通讯:如何跳出传统思维来设计聊天室架构?
因为视频直播业务的大规模扩张,聊天室这种功能在最近几年又火了起来.本篇文章将会重点挑选聊天室这个典型场景,和大家分享一下网易云信在实现这个功能时是如何做架构设计的. 相关推荐阅读几十万人同时在线的直播 ...
- 多线程与高并发(三)synchronized关键字
上一篇中学习了线程安全相关的知识,知道了线程安全问题主要来自JMM的设计,集中在主内存和线程的工作内存而导致的内存可见性问题,及重排序导致的问题.上一篇也提到共享数据会出现可见性和竞争现象,如果多线程 ...
- Spring+Redis配置
既上次把同事屁屁龙的tomcat数据源文档摘抄过来之后,这次获得其同意后,再次怀着感激涕零的心情,抄个爽. 全文非本人所写,所以若转载时,请标明文章来源于本人原创(不要脸真爽哈哈哈哈),谢谢! 1.j ...
- 如何让apache支持.htaccess 解决Internal Server Error The server …错误
如何让apache支持.htaccess 解决Internal Server Error The server …错误 文章来源:小灰博客| 时间:2013-12-25 12:17:08| 作者:Le ...
- JAVA Stirng.format 使用理解
JAVA Stirng.format 使用理解前言:项目中需要对一些字符串处理发现format方法的神奇之处一.api才是王道第一种二参使用①public static String format(S ...
- iOS中 分类(category)与扩展(Extension)的区别?
1.分类(category)的作用 (1).作用:可以在不修改原来类的基础上,为一个类扩展方法.(2).最主要的用法:给系统自带的类扩展方法. 2.分类中能写点啥? (1).分类中只能添加“方法”,不 ...
- 设计模式-享元模式(Flyweight)
享元模式是构造型模式之一,它通过与其他类似对象共享数据来减少内存占用 角色和职责: 1.抽象享元角色()-Person: 享元角色的公共接口 2.具体享元角色()-Teacher: 抽象享元角色的 ...
- Docker环境下的前后端分离项目部署与运维(十二)使用Portainer管理Docker
安装 docker hub地址:https://hub.docker.com/r/portainer/portainer/ # 每台服务器都要安装 docker pull portainer/port ...
- JavaSE核心知识
一:Java简介 1. Java语言的介绍:Java是一门面向对象编程语言,具有功能强大和简单易用两个特征. 2. Java语言的特点:简单性.面向对象.分布式.健壮性.安全性.平台独立与可移植性.多 ...
- 性能测试-实例讲解VU、RPS、RT公式换算
概述 今天看到一篇文章讲解VU.RPS.RT,中间有一个公式如下图 并发数 = RPS * 响应时间 于是我在本地做了几次实验,试图验证一下公式的准确性 实验网站 www.baidu.com 第一次 ...