react native优化class组件的几个方法。优化渲染时间,减少渲染次数

该博客围绕优化React渲染性能展开。先明确优化目的为提升渲染速度、减少渲染次数,接着阐述优化流程,包括梳理组件结构,针对渲染时间和次数提出具体优化内容,如避免内联定义、记忆组件等。最后通过前后对比展示优化效果,也指出了emulator受网络和CPU影响大、真机无法用filpper的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 目的:

  • 优化渲染速度
  • 减少渲染次数

2. 优化流程:

2.1 梳理组件结构

优化后的结构图
–略

2.2 需要优化的内容

针对渲染时间和渲染次数进行优化

减少渲染时间:

  1. 避免内联函数定义 → 每次重新渲染都重新创建函数实例,VDom属性改变,dom节点重新渲染。
//bad: onClick方法中,使用了内联匿名函数
<Comp onClick={(e)=>{this.setState({isClick:ture})}} key={item.id}/>

//good: 声明函数
const handleClick = (e) => this.setState({isClick:ture})

<Comp onClick={handleClick} key={item.id}/>
  1. 避免内联组件定义 → 每次都重复创建匿名组件实例,引起Comp VDom变更,dom节点重新渲染
//bad: onClick方法中,使用了内联匿名组件
<Comp prop={<View props={this.state.name}> ... </View>} key={item.id}/>

//good: 声明组件
const propComp = (props: {name}) => (<View props={name}> ... </View>)

<Comp prop={propComp} key={item.id}/>
  1. 避免内敛style定义 → 更新vdom,重新渲染
//bad : 
<Comp style={{flex: 1}} />

//good: 

flex: {
	flex: 1
}

<Comp style={flex} />
  1. 减少render函数内声明 → 每次重新渲染都会执行render函数,在render函数中定义子组件或方法,会增加每次重新渲染耗时。若是较大的组件或等待方法,耗时更明显

    //bad: 每次重新渲染都会重新创建navBarLeftRender与handlePageBack
    class ScanList extends React.Component<ScanListProps, ScanListState> {
    	...
    	...
    	render() {
    		const navBarLeftRender = (
    			<TouchableOpacity
    				onPress={hadnlePageBack}
    				... 
    			/>
    		)
    		const handlePageBack = async() => {
    			await this.props?.onBack?.();
    		}
    	
    		return (
    			<View>
    				<NavBar leftProps={navBarLeftRender} />
    				...
    			</View>
    		)
    	}
    }
    
    //good: 将render中声明的函数与组件都拿到render外
    class ScanList extends React.Component<ScanListProps, ScanListState> {
    	...
    	const navBarLeftRender = (
    		<TouchableOpacity
    			onPress={hadnlePageBack}
    			... 
    		/>
    	)
    	const handlePageBack = async() => {
    		await this.props?.onBack?.();		
    	}
    	...
    	render() {
    	...	
    		return (
    			<View>
    				<NavBar leftProps={navBarLeftRender} />
    				...
    			</View>
    		)
    	}
    }
    
  2. 记忆子组件 → 在引用的props不变更的情况下,不因父组件重新渲染而引起子重新渲染。

    //bad: 无论leftProps是否更新,NavBar总是随着ScanList组件重新渲染。
    	render() {
    	...	
    		return (
    			<View>
    				<NavBar leftProps={navBarLeftRender} />
    				...
    			</View>
    		)
    	}
    
    //good: 只在leftProps更新时渲染
    const MemoNavBar = memo(NavBar)
    	render() {
    	...	
    		return (
    			<View>
    				<MemoNavBar leftProps={navBarLeftRender} />
    				...
    			</View>
    		)
    	}
    
    
  3. 长列表优化 → 目前组件用到的flatList没有使用官方推荐的优化属性, 如: maxToRenderPerBatch, initialNumToRender

减少渲染次数:

引起重新渲染主要场景:

  1. 组件状态变更[略]

  2. 父组件渲染导致子组件重新渲染

    1. 梳理出每个子组件使用到的state,状态下放。

      //bad: 若点击button,会触发整个Component的更新,导致veryslowComponent也重新渲染
      const Component = () => {
      	const [open, setOpen] = useState(false);
      	return (
      		<Something>
      			<Button onClick={()=> setOpen(true)}
      			{isOpen && <ModalDialog />}
      			<VerySlowComponent />
      		</Something>
      	)
      }
      
      //good: 将只作用在Dialog的open state集中到ButtonWithDialog中
      //open更新只引起ButtonWithDialog的重新渲染, VerySlowComponent不受影响
      
      const ButtonWithDialog = () => {
      	const [open, setOpen] = useState(false);
      	return (
      		<>
      			<Button onCLick={() => setOpen(true)} />
      			{isOpen && <ModalDialog />}
      		</>
      	)
      }
      const Component = () => {
      	return (
      		<Something>
      			<ButtonWithDialog />
      			<VerySlowComponent />
      		</Something>
      	)
      }
      
    2. 记忆组件

      通过PureComponent,或者memo,或者shouldComponentUpdate 控制class组件是否有必要重新渲染。

    3. 基于b,使用组件的页面,若每次都传入重新定义的pure function可以使用usecallback , usememo,减少引起scanList重新渲染次数

  3. context变更导致引用的组件重新渲染[略]

  4. hooks内状态变更触发重新渲染[略]

3. 具体优化内容

-略

4 前后对比

通过flipper performace记录优化后的各项值,前后对比

最终优化性能对比:

直观的火焰图: 可以看到渲染次数和渲染时间都比初始大大减少

在这里插入图片描述
页面操作耗时对比:
在这里插入图片描述

5. 遗留:

emulator随网络波动,cpu运行情况 影响大,同一修改节点,刷新前后渲染时长有较大差异,用真机更可靠,但目前真机无法使用filpper的profilling。

### React Native 组件优化策略 #### 一、理解渲染机制的重要性 为了有效避免不必要的重复渲染,深入理解React渲染机制至关重要。当状态或属性发生变化时,React会重新渲染受影响的组件及其子组件。如果这些变化频繁发生而未加控制,则可能导致性能瓶颈[^1]。 #### 二、采用函数式组件与Hooks替代类组件 现代版本的React推荐使用函数式组件配合Hooks来代替传统的类组件形式。这种方式不仅简化了代码结构,而且通过`useMemo()` 和 `useCallback()` Hooks可以更精细地管理依赖关系,从而减少因父级传递下来的props改变所引起的子组件无意义更新。 ```javascript import React, { useMemo } from 'react'; function MyComponent({ data }) { const processedData = useMemo(() => processData(data), [data]); return ( // JSX here... ); } ``` #### 三、合理运用PureComponent/React.memo高阶组件 对于那些仅基于prop的变化决定是否应该再次渲染的情况,可以选择继承自`React.PureComponent`或者包裹一层`React.memo`。这两种方式都会自动执行浅比较操作,在前后两次接收相同参数时不触发新的渲染流程。 ```javascript // 使用 PureComponent 来防止不必要的渲染 class Child extends React.PureComponent { render() { console.log('Child rendered'); return <div>{this.props.value}</div>; } } // 或者使用 memo 函数组件 const MemoizedChild = React.memo(function Child(props) { console.log('Child rendered'); return <div>{props.value}</div>; }); ``` #### 四、利用shouldComponentUpdate生命周期方法(针对Class Component) 在某些情况下可能需要更加复杂的逻辑判断当前实例是否有必要进行重绘工作。此时可以在Class Component内部覆写`shouldComponentUpdate(nextProps,nextState)` 方法来自定义条件。 ```javascript shouldComponentUpdate(nextProps, nextState){ if (nextProps.someProp !== this.props.someProp || nextState.someState !== this.state.someState ) { return true; } return false; } ``` #### 五、考虑虚拟化列表和其他UI模式 当处理大量数据项展示时,比如长列表滚动场景下,应优先选用支持按需加载更多项目的第三方库如`react-window`或内置FlatList组件中的windowSize prop设置以实现部分可见区域内的高效渲染效果[^2]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值