使用immutable和react-immutable-render-mixin优化React Native视图渲染

想知道React Native是什么?先移步官网。另外,本文部分内容参考了搞定immutable.js

熟悉React.js的都应该知道,React.js是一个UI = f(states)的框架,为了解决更新的问题,React.js使用了virtual dom,virtual dom通过diff修改dom,来实现高效的dom更新。听起来很完美吧,但是有一个问题。当state更新时,如果数据没变,你也会去做virtual dom的diff,这就产生了浪费,可以参考flummox这篇文章

React Native的视图刷新机制和React一脉相承,官方文档中抛出了PureRenderMixin,因为PureRenderMixin只是简单的浅比较,不适用于多层比较,所以对于一些特殊情况解决不了问题,而react-immutable-render-mixin则可以直接比较immutable对象的hashcode,既可以进行深层次比较,又大大的提高了比较速度。另外,关于immutable.js的使用方法,这里不赘述,可以自行查阅官方文档

直接上代码了。

package.json引入两个包

"immutable": "^3.8.1",
"react-immutable-render-mixin": "^0.9.7",

创建3个组件,ViewOne、ViewTwo、ViewThree。

/**
 * ViewOne
 * @flow
 */

import React, {Component} from 'react';
import {Text, View} from 'react-native';
import { shallowEqualImmutable } from 'react-immutable-render-mixin';

import * as StyleSheet from 'MallStyleSheet';

export default class ViewOne extends Component {

    // 构造
    constructor(props) {
        super(props);
    }

    shouldComponentUpdate(nextProps, nextState) {
        return !shallowEqualImmutable(this.props, nextProps)
            || !shallowEqualImmutable(this.state, nextState);
    }

    render() {
        console.log('render in ViewOne');
        return (
            <View style={styles.container}>
                <Text style={styles.welcome}>
                    {this.props.content}
                </Text>
            </View>
        );
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: '#F5FCFF',
        justifyContent: 'center',
        alignItems: 'center'
    },
    welcome: {
        fontSize: 20,
        textAlign: 'center',
        margin: 10
    }
});
/**
 * ViewTwo
 * @flow
 */

import React, {Component} from 'react';
import {Text, View} from 'react-native';
import { shallowEqualImmutable } from 'react-immutable-render-mixin';

import * as StyleSheet from 'MallStyleSheet';

export default class ViewTwo extends Component {

    // 构造
    constructor(props) {
        super(props);
    }

    shouldComponentUpdate(nextProps, nextState) {
        return !shallowEqualImmutable(this.props, nextProps)
            || !shallowEqualImmutable(this.state, nextState);
    }

    render() {
        console.log('render in ViewTwo');
        return (
            <View style={styles.container}>
                <Text style={styles.welcome}>
                    {this.props.content.name}
                </Text>
            </View>
        );
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: '#F5FCFF',
        justifyContent: 'center',
        alignItems: 'center'
    },
    welcome: {
        fontSize: 20,
        textAlign: 'center',
        margin: 10
    }
});
/**
 * ViewThree
 * @flow
 */

import React, {Component} from 'react';
import {Text, View} from 'react-native';
import { shallowEqualImmutable } from 'react-immutable-render-mixin';

import * as StyleSheet from 'MallStyleSheet';

export default class ViewThree extends Component {

    // 构造
    constructor(props) {
        super(props);
    }

    shouldComponentUpdate(nextProps, nextState) {
        return !shallowEqualImmutable(this.props, nextProps)
            || !shallowEqualImmutable(this.state, nextState);
    }

    render() {
        console.log('render in ViewThree');
        return (
            <View style={styles.container}>
                <Text style={styles.welcome}>
                    {this.props.content.get('name')}
                </Text>
            </View>
        );
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: '#F5FCFF',
        justifyContent: 'center',
        alignItems: 'center'
    },
    welcome: {
        fontSize: 20,
        textAlign: 'center',
        margin: 10
    }
});

在render()函数打印了log,组件只是渲染了文本。
把组件插入到主界面。

/**
 * NextScreen
 * @flow
 */

import React, {Component} from 'react';
import {View} from 'react-native';
import Button from 'react-native-button';
import {Map} from 'immutable';

import * as StyleSheet from 'MallStyleSheet';
import {BlueNavBar} from 'MallNavBar';
import ViewOne from './ViewOne';
import ViewTwo from './ViewTwo';
import ViewThree from './ViewThree';

export default class NextScreen extends Component {

    // 构造
    constructor(props) {
        super(props);
        this.state = {
            buttonTitle: '修改',
            viewOne: 'ViewOne',
            viewTwo: {name: 'ViewTwo'},
            viewThree: Map({name: 'ViewThree'})
        };
        this._changState = this._changState.bind(this);
        this._resetState = this._resetState.bind(this);
    }

    _changState() {
        // 由于 immutable 内部使用了 Trie 数据结构来存储,只要两个对象的 `hashCode` 相等,值就是一样的。这样的算法避免了深度遍历比较,性能非常好。
        this.setState({
            buttonTitle: '再次修改',
            viewOne: 'ViewOne changed!',
            viewTwo: {name: 'ViewTwo changed'},
            viewThree: this.state.viewThree.set('name', 'ViewThree changed')
        });
    }

    _resetState() {
        this.setState({
            viewOne: 'ViewOne',
            viewTwo: {name: 'ViewTwo'},
            viewThree: this.state.viewThree.set('name', 'ViewThree')
        });
    }

    render() {
        return (
            <View style={styles.container}>
                <BlueNavBar title={this.props.title}/>
                <View style={styles.content}>
                    <Button containerStyle={styles.touch}
                            style={styles.textEnter}
                            onPress={() => {this._changState();}}>
                            {this.state.buttonTitle}
                    </Button>
                    <Button containerStyle={styles.touch}
                            style={styles.textEnter}
                            onPress={() => {this._resetState();}}>
                            恢复
                    </Button>
                    <ViewOne content={this.state.viewOne}/>
                    <ViewTwo content={this.state.viewTwo}/>
                    <ViewThree content={this.state.viewThree}/>
                </View>
            </View>
        );
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: '#F5FCFF'
    },
    content: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
    },
    touch: {
        width: 90,
        height:32,
        marginTop: 10,
        alignItems: 'center',
        justifyContent: 'center',
        borderRadius:3,
        backgroundColor:'purple'
    },
    textEnter: {
        fontSize: 16,
        color: 'white'
    }
});

运行结果
初次渲染的时候,三个子组件都渲染了。


Paste_Image.png


点击修改按钮,因为三个子组件的props都变了,一样重新做了渲染。


Paste_Image.png


点击再次修改按钮,通过比较只有组件2的props发生了变化,故而只渲染了ViewTwo,就算点击n次再次修改,也只会重新渲染ViewTwo。


Paste_Image.png


从代码中我们可以看到,ViewOne的props是字符串,因此浅比较可以对比出再次修改以后内容没有发生改变。ViewTwo的props是对象,浅比较只会比较到content的内容指向的对象,因为对象发生了改变,所以ViewTwo会重新渲染,尽管新对象的key和value值都没有变化。ViewThree使用了immutable对象作为props,基于hashcode的对比可以从深层次比较两个对象内容是否一致,从而快速准确的判断是否需要重新渲染。



本文原地址:http://www.jianshu.com/p/de281343610c?open_source=weibo_search

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值