从业务性能角度思考 React 组件的更新方式

前言

最近在维护公司一个老项目 React 工程(体积庞大),主要工作内容是对工程内的一些用户体验做调整和优化。

由于最初搭建程序数据流设计上的不完善以及开发人员的技术水平存在一定差距,用户反馈 Input 输出框 change 事件输入存在卡顿,且页面响应延迟。

这对于用户使用,或者作为开发人员来说也是不能够接受的。

本文将自上而下记录这一优化过程。

背景

一个应用页面存在非常多的模块内容(组件),每个模块所依赖数据结构包括层级非常复杂(关键),每个模块都或多或少会读取全局状态管理(dva)中的 state,使用效果可能如下:

export default connect(state => state)(Component); 

而对于页面上的输入框,Input onChange 事件每次都会通过修改全局状态池(dva)中的数据方式达到视图更新。

大家可以想到,如果采用这种更新视图方式,一次键盘输入,都可能会导致页面所有模块接收到通知去进行更新。

这个更新是大范围的,更新计算以及重渲染视图都需要时间,但用户操作仅仅是 Input 这一小块区域,这就造成了输入框输入卡顿延迟问题。

分析

上述背景可以得知是由于使用了不合理的更新方式导致页面卡顿。

这时我们就会想到:如果进行小范围的视图更新,比如在发生 onChange 时只有 Input 这个组件进行视图更新,不用影响到其他组件的更新。

通常,我们都会对 Input 进行二次封装组件:接收 props.value 作为初始值,组件内部拥有自己的 state 变量,每次 change 时只需更新本组件 state 来触发输入框的视图更新。

另外对于更新 props.value,可借助对象引用地址特征,在 props.value 所在的顶层对象中同步 value 值的更新。这样就实现了仅 Input 组件小范围更新。

下面我们开始敲些代码加深理解。为了模拟场景,我们编写三个组件:Canvas(画布)、Setter(右侧设置区)、Input(设置区的输入框)。

其中 dva 中的数据我们使用 React.createContext Provide 方式来代替,由于工程技术偏老,代码中我们采用 class 组件 来完成组件编写。

代码

首先,我们可以通过 create-react-app 创建一个应用,在入口文件 index.js 中通过 ReactContext.Provider 将数据向下传递:

// src/reactContext.js
import React from 'react';
export default React.createContext();

// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import Setter from './Setter';
import Canvas from './canvas';
import ReactContext from './ReactContext';

const block = { name: '输入框', value: '' };

ReactDOM.render(<ReactContext.Provider value={
  { block }}><Canvas /><Setter /></ReactContext.Provider>, document.getElementById('root')
); 

接着,我们封装 Input 组件并且在内部维护自己的 state,实现可能如下:

// src/Input.js
import React from 'react';

class Input extends React.PureComponent {constructor(props) {super(props);this.state = {value: props.value || props.defaultValue || '',}}componentWillReceiveProps(newProps) {if (newProps.value !== this.state.value) {this.setState({ value: newProps.value });}}handleChange(event) {const value = event.target.value;this.setState({ value });this.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
React 中,有多种方式可以实现组件之间的值传递。以下是一些常见的方式: 1. Props(属性):通过在父组件中给子组件传递属性,子组件可以通过 props 对象来获取这些属性值。父组件中的属性变化会触发子组件的重新渲染。 2. State(状态):每个组件都有自己的状态对象,可以通过 setState 方法更新状态并触发重新渲染。父组件可以通过 props 将状态值传递给子组件,并通过回调函数来修改父组件的状态。 3. Context(上下文):Context 提供了一种在组件树中共享数据的方式,可以在父组件中创建一个 Context 对象,并通过 Provider 组件将数据传递给子组件。子组件可以通过 Consumer 组件或 useContext 钩子来访问这些数据。 4. Redux 或其他状态管理库:使用 Redux 或其他状态管理库可以将应用的状态集中管理,并通过提供的 API 来进行状态的读取和更新。这样不同组件之间可以共享和传递状态,而不需要通过 props 层层传递。 5. 发布订阅模式或事件总线:可以使用发布订阅模式或事件总线来实现组件之间的解耦和通信。一个组件可以发布一个事件,其他组件可以订阅该事件并执行相应的操作。 这些是常见的组件间传值方式,选择哪种方式取决于具体的场景和需求。在实际开发中,根据项目的规模和复杂度,选择合适的方式来进行组件间的数据传递。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值