shouldComponentUpdate 如何比较能动态传参的function

最近在做性能优化。基于 shouldComponentUpdate 来做比较。对于数据来说可以很容易比较(用了immutable)。

然而对于某些function来说怎么处理呢?

要求:能够动态传参v

假设有伪代码

class A extends React.Component{
    constructor(props) {
        super(props);
    }
    
    handleB(value){
        console.log(value);
    }
    
    render(){
        return <div>
            {[1,2,3].map(v => <B onCallback={this.handleB.bind(this, v)} />)}
        </div>
    }
}

class B extends React.Component {
    shouldComponentUpdate(nextProps){
        const thisProps = this.props;
        
        // ....省略
        
        if(thisProps.onCallback === nextProps.onCallback){
            return false;
        }
        return true;
    }
    render(){
        return ....省略;
    }
}

补充: 感谢大家,最终用了如下方案

class A extends React.Component{
    constructor(props) {
        super(props);
        this.handleB = ::this.bindB;
    }
    
    handleB(event){
        // 有了索引,就可以查到原数据了
        console.log(event.currentTarget.dataset.index); 
    }
    
    render(){
        return <div>
            {[1,2,3].map((v, i) => <B data-index={i} onCallback={this.handleB} />)}
        </div>
    }
}
阅读 3.9k
2 个回答

data- 来存参数

class Demo extends Component {
    constructor(props) {
        super(props);

        this.clickHandler = this.clickHandler.bind(this);
    }

    render() {
        const arr = [0, 1, 2];

        return (
            <div>
                {
                    arr.map(i => (
                        <button
                            key={i}
                            data-index={i}
                            onClick={this.clickHandler}
                        />
                    ))
                }
            </div>
        )
    }

    clickHandler(e) {
        const index = e.currentTarget.dataset.index;
    }
}

我们先来看这么几个问题

如果props是一个函数,能否用immutable那套比较reference的方式来判断

答案是:能。因为函数在javascript里是一等公民,所谓一等公民就是可以被赋值给变量;而且函数本身也是一种特殊的Object,当然可以通过reference来比较,思路没有错

动态传參

map函数在每次迭代时,就会自动调用callback,并传入参数currentValueindexarray,如下图:

图片描述

所以动态穿參从来不是问题

bind的问题

你在A里的this.handleB.bind(this, v)确实有一点点小问题,因为bind会返回一个新的函数,这将导致你的if(thisProps.onCallback === nextProps.onCallback){永远不成立,无论A的哪个状态发生变化,bind都会生成一个新的handleB,那thisProps.onCallback === nextProps.onCallback结果就是false,即便对你来说根本没改过handleB

修正:

不好意思,之前关于v这个部分看得不够仔细,重新看了一下,我是这么理解的:

既然你要里列表形式展示B组件,那参照官方dynamic-children的写法,给组件增加一个key属性,然后在组件B内部通过key属性,在B组件内部调用onCallback的时候,把key的值带回给A组件传入的函数才是可取之道。

所以A需要这么调整下:

class A extends React.Component{
    constructor(props) {
        super(props);
        //构造实例时绑定一次就好了
        this.handleB = this.handleB.bind(this);
    }
    
    handleB(value){
        console.log(value);
    }
    
    render(){
        //下面用的就是同一个handleB函数
        return <div>
            {[1,2,3].map(v => <B key={v} onCallback={this.handleB} />)}
        </div>
    }
}

B做如下调整:

class B extends React.Component {
    shouldComponentUpdate(nextProps){
        const thisProps = this.props;
        
        // ....省略
        
        if(thisProps.onCallback === nextProps.onCallback){
            return false;
        }
        return true;
    }
    
    test(){
         //假设这个test方法就是B里处理onCallback的地方,可以这么写:
         this.props.onCallback(this.props.key);
    }
    
    render(){
        return ....省略;
    }
}

我太久不写react了,语法可能不太对,但思路是对的。鉴于你自己会写react,语法如果有问题,自行调整吧

推荐问题
宣传栏