速来报名!AICon北京站鸿蒙专场~ 了解详情
写点什么

乾坤大挪移!React 也能 “用上” computed 属性

  • 2021-02-01
  • 本文字数:2395 字

    阅读完需:约 8 分钟

乾坤大挪移!React 也能 “用上” computed 属性

前言,关于计算属性

初次见到计算属性一词,是在 Vue 官方文档 《计算属性和侦听器》 一节中,文章中是这样描述计算属性的:


模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。


回想我们编写的 React 代码,是否也在 JSX(render 函数)中放入了太多的逻辑导致 render 函数过于庞大,难以维护?


React 中的计算属性


说到 React 之前,我们先看下 Vue,在 Vue 中,计算属性主要有以下两点特性:


  1. 计算属性以声明的方式创建依赖关系,依赖的 data 或 props 变更会触发重新计算并自动更新。

  2. 计算属性是基于它们的响应式依赖进行缓存的。


而在 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() { returnthis.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 的介绍在 这里(https://zh-hans.reactjs.org/docs/hooks-reference.html#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 支持,但得益于活跃的社区,工作中遇到的问题总能找到解决方案。且在摸索这些解决方案的同时,我们还能学习到诸多经典的编程思想,帮助我们更合理的运用框架,用技术解决业务问题。



头图:Unsplash

作者:不二

原文:https://mp.weixin.qq.com/s/Fv69IvuR4FhyFQbLO7DLMg

原文:乾坤大挪移!React 也能 “用上” computed 属性

来源:政采云前端团队 - 微信公众号 [ID:Zoo-Team]

转载:著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

2021-02-01 00:002421

评论

发布
暂无评论
发现更多内容

PANews与NFTScan联合推出Top50 NFT Collection全球影响力榜单

NFT Research

Ethereum NFT

网易易盾 GameSentry 正式开源,做游戏安全保障的尖兵利刃

网易智企

安全 测试

为超级品牌打造「上瘾算法」|Whale 帷幄发布全新 DAM & VAP 内容数字化产品

科技热闻

计算机网络——码元、波特

StackOverflow

编程 计算机网络 9月月更

MODBUS RTU 485 协议简要说明

矜辰所致

Modbus RS485 9月月更

送你5个MindSpore算子使用经验

华为云开发者联盟

人工智能 算子 企业号九月金秋榜

SAP ABAP 平台新的编程模型

汪子熙

SAP abap Netweaver 思爱普 9月月更

3D打印机打印模型的10大技巧

Dylan

3D模型

住宅代理IP在网络攻击中的作用

郑州埃文科技

代理IP 安全检测 撞库攻击

阿里云视觉智能开放平台离线人脸识别SDK开启邀测啦

夏夜许游

人工智能 AI 人脸识别 离线包

实操指南:如何为 SAST 工具设置误报基准?

SEAL安全

应用安全 静态应用安全测试 SAST 应用安全测试 软件供应链安全

【死磕JVM】用Arthas排查JVM内存 真爽!我从小用到大

Java快了!

阿里云视觉智能开放平台商品图智能生成开启邀测啦

夏夜许游

人工智能 AI 电商 图像分割

iofod - Echart 图表全支持

iofod jude

Java 前端 低代码

资源使用率提高25%,成本降低90%,云函数是怎么做到的?

最新动态

数据库发展史2--数据仓库

数据库 数据仓库 叶正盛 玖章

压测平台在全链路大促压测中的实践

得物技术

中间件 全链路压测 QPS 企业号九月金秋榜

“基础-中级-高级”Java程序员面试合集,看完献出我的膝盖!

收到请回复

Java 云计算 开源 架构 编程语言

Github星标90K!京东架构师一篇讲明白百亿级并发系统架构设计

了不起的程序猿

Java 程序员 高并发 java程序员 高并发系统设计

阿里云视觉智能开放平台2D视频转3D视频开启邀测啦

夏夜许游

人工智能 AI 3D

Pipy + Sentinel 实现 Redis 的高可用

Flomesh

Service Mesh 服务网格

【HTML-CSS】小游戏--渣灰哥的愿望之砍砍渣灰

Sam9029

JavaScript HTML5, CSS3 9月月更

论监控中事件管理的艺术

穿过生命散发芬芳

事件管理 9月月更

Spring 框架使用了哪些设计模式?

Java快了!

spring框架

华为云宣布全面建设全球初创生态,3年内赋能10000家高潜初创企业

华为云开发者联盟

云计算 创业 创新创业 企业号九月金秋榜

编译器优化:何为别名分析

华为云开发者联盟

开发 编译器 企业号九月金秋榜

TCPIP协议栈的心跳、丢包重传、连接超时机制实例详解

Java快了!

怎样才能开一场高效的迭代评审会?

LigaAI

Scrum 迭代 LigaAI 敏捷实践 企业号九月金秋榜

JWT本无状态,为何却要存储在Redis破坏其无状态特性?

知识浅谈

JWT 9月月更

心血来潮,手绘一张Spring学习思维,内容详细全面,秋招面试必看!

收到请回复

Java 云计算 开源 架构 编程语言

现代数据栈如何降低数据平台的复杂度?

Kyligence

数据分析 云原生 指标中台 指标自动化

乾坤大挪移!React 也能 “用上” computed 属性_大前端_政采云前端团队_InfoQ精选文章