乾坤大挪移!React 也能 “用上” computed 属性
前言,关于计算属性
初次见到计算属性一词,是在 Vue 官方文档 《计算属性和侦听器》 一节中,文章中是这样描述计算属性的:
模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。
回想我们编写的 React 代码,是否也在 JSX(render 函数)中放入了太多的逻辑导致 render
函数过于庞大,难以维护?
React 中的计算属性
说到 React 之前,我们先看下 Vue,在 Vue 中,计算属性主要有以下两点特性:
- 计算属性以声明的方式创建依赖关系,依赖的 data 或 props 变更会触发重新计算并自动更新。
- 计算属性是基于它们的响应式依赖进行缓存的。
而在 React 中,计算属性也是经常可见,相信各位熟悉 React 的读者都写过类似下面的代码:
import React, { Fragment, Component } from 'react'; class Example extends Component { state = { firstName: '', lastName: '', }; render() { // 在 render 函数中处理逻辑 const { firstName, lastName } = this.state; const fullName = `${firstName} ${lastName}`; return <Fragment>{fullName}</Fragment>; } }
在上面的代码里,render 函数里的 fullName
依赖了 props
中的 firstName
和 lastName
。firstName
或 lastName
变更之后,变量 fullName
都会自动更新。其实现原理是 props 以及 state 的变化会导致 render 函数调用,进而重新计算衍生值。
虽然能实现计算,但我们还是把计算逻辑放入了 render 函数导致了它的臃肿,这并不优雅。更好的做法是把计算逻辑抽出来,简化 render 函数逻辑:
class Example extends Component { state = { firstName: '', lastName: '', }; // 把 render 中的逻辑抽成函数,减少render函数的臃肿 renderFullName() { const { firstName, lastName } = this.state; return `${firstName} ${lastName}`; } render() { const fullName = this.renderFullName(); return <Fragment>{fullName}</Fragment>; } }
如果你对 Vue 很了解,你肯定知道其 computed 计算属性,底层是使用了getter,只不过是对象的 getter。那么在 React 中,我们也可以使用类的 getter 来实现计算属性:
class Example extends Component { state = { firstName: '', lastName: '', }; // 通过getter而不是函数形式,减少变量 get fullName() { const { firstName, lastName } = this.state; return `${firstName} ${lastName}`; } render() { return <Fragment>{this.fullName}</Fragment>; } }
进一步,使用 memoization 优化计算属性
上文有提到在 Vue 中计算属性对比函数执行,会有缓存,减少计算。因为计算属性只有在它的相关依赖发生改变时才会重新求值。
这就意味着只要 firstName 和 lastName 还没有发生改变,多次访问 fullName 计算属性会立即返回之前的计算结果,而不必再次执行函数。
对比之下,React 的 getter 是否也有缓存这个优势??? 答案是:没有。React 中的 getter 并没有做缓存优化!
不过不用失望,我们可以使用记忆化技术(memoization)来优化我们的计算属性,达到和 Vue 中计算属性一样的效果。我们需要在项目中引入 memoize-one 库,代码如下:
import memoize from 'memoize-one'; import React, { Fragment, Component } from 'react'; class Example extends Component { state = { firstName: '', lastName: '', }; // 如果和上次参数一样,`memoize-one` 会重复使用上一次的值。 getFullName = memoize((firstName, lastName) => `${firstName} ${lastName}`); get fullName() { return this.getFullName(this.state.firstName, this.state.lastName); } render() { return <Fragment>{this.fullName}</Fragment>; } }
再进一步,使用 React Hooks 优化计算属性
上文在 React 中使用了 memoize-one 库实现了类似 Vue 计算属性(computed)的效果 —— 基于依赖缓存计算结果。得益于React 16.8 新推出的 Hooks 特性,我们可以对逻辑进行更优雅的封装,对 Hooks 还不够了解的小伙伴可以先阅读我们团队另一篇文章 《看完这篇,你也能把 React Hooks 玩出花》
此处,我们需要用到 useMemo
。官方对 useMemo
的介绍在 这里,详情请移步查看。简单的说,就是我们传入一个 回调函数 和一个 依赖列表,React 会在依赖列表中的值变化时,调用这个回调函数,并将回调函数返回的结果进行缓存:
import React, { useState, useMemo } from 'react'; function Example(props) { const [firstName, setFirstName] = useState(''); const [lastName, setLastName] = useState(''); // 使用 useMemo 函数缓存计算过程 const renderFullName = useMemo(() => `${firstName} ${lastName}`, [ firstName, lastName, ]); return <div>{renderFullName}</div>; }
总结
本文介绍了在 React 中如何实现类似 Vue 计算属性(computed)的效果 —— 基于依赖缓存计算结果,实现逻辑计算与视图渲染的解耦,降低 render 函数的复杂度。
从业务开发角度来讲,Vue 提供的 API 极大地提高了开发效率。React 虽然在某些场景下,没有官方的同类原生 API 支持,但得益于活跃的社区,工作中遇到的问题总能找到解决方案。且在摸索这些解决方案的同时,我们还能学习到诸多经典的编程思想,帮助我们更合理的运用框架,用技术解决业务问题。
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
基于SpringCloudAlibaba和Nacos微服务体系下的FeignClient客户端负载均衡入门实例
本文主要介绍在SpringCloudAlibaba和Nacos微服务框架下,使用openfeign的FeignClient实现客户端负载均衡的效果。关于服务提供者和服务消费者的程序请直接查阅这篇文章。基于SpringCloudAlibaba和Nacos构建微服务入门实例 OpenFeign简介 Feign is a Java to HTTP client binder inspired by Retrofit, JAXRS-2.0, and WebSocket. Feign's first goal was reducing the complexity of binding Denominator uniformly to HTTP APIs regardless of ReSTfulness. 打包服务提供者程序 将基于SpringCloudAlibaba和Nacos构建微服务入门实例中的服务提供者程序打包输出:myclouds-nacos-discovery-provider-example-3.0.0.jar。 启动2个服务提供者实例 java -jar myclouds-na...
- 下一篇
PhalApi 2.9.1 版本发布,PHP 开源接口框架
[主要更新] 1、特别注意:数据库查询返回结果默认都为字符串类型,优化为自动类型匹配,如整型。如果不需要开启,则可添加dbs.servers.db_master.pdo_attr_string配置项为true,> 则可以保持原来继续返回为字符串的数据库结果。如果出现:the database server cannot successfully prepare the statement 错误,请进行调试并手动检测SQL的语法正确性。 2、对于接口参数规则,增加解析后的回调函数配置on_after_parse,支持多个函数名的管道配置和回调函数配置,详细请见文档说明[解析后回调函数 on_after_parse](http://docs.ph alapi.net/#/v2.0/api-params?id=%e5%85%ac%e5%85%b1%e5%8f%82%e6%95%b0%e9%85%8d%e7%bd%ae%e9%80%89%e9%a1%b9) 3、添加日志接口示例 [辅助更新] 1、迁移User扩展到2.x,phalapi/user 2、日志文件在di初始化时,若缺少目录权...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
-
Docker使用Oracle官方镜像安装(12C,18C,19C)
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS8编译安装MySQL8.0.19
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- MySQL8.0.19开启GTID主从同步CentOS8
- CentOS7,8上快速安装Gitea,搭建Git服务器
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
推荐阅读
最新文章
- CentOS7设置SWAP分区,小内存服务器的救世主
- 设置Eclipse缩进为4个空格,增强代码规范
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS6,CentOS7官方镜像安装Oracle11G
- Hadoop3单机部署,实现最简伪集群
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- CentOS7安装Docker,走上虚拟化容器引擎之路