Skip to content

nanachi的REF问题解决

司徒正美 edited this page Jan 15, 2019 · 1 revision

在小程序,由于页面组件不能直接引入业务组件,业务组件已经在index.json中通过usingComponents引入了。 这时nanachi通过useComponent解决了

比如说

import React from '@react';
import YButton from '@components/YButton/index';
import './index.scss';

class P extends React.Component {
    constructor() {
        super();
        this.state = {
            condition1: true,
            condition2: true
        };
    }

    toggleCondition2() {
        this.setState({
            condition2: !this.state.condition2
        });
    }

    toggleCondition1() {
        this.setState({
            condition1: !this.state.condition1
        });
    }
    componentDidMount(){
        console.log(this.refs.aaa, 'componentDidMount');
    }
    render() {
        return (
            <div class='anu-block xxx'>
                <div class='anu-block'>
                    <div>Condition1 active</div>
                    <YButton ref="aaa" id="ybutton" onTap={this.toggleCondition1.bind(this)}>
                                    Inactive Condition1
                    </YButton>
                    <div>Condition2 active</div>
                    <YButton onTap={this.toggleCondition2.bind(this)}>
                                    Inactive Condition2
                    </YButton>
                </div> 
            </div>
        );
    }
}

export default P;

被编译成

import React from '../../../../ReactWX.js';

function P() {
    this.state = {
        condition1: true,
        condition2: true
    };
}

P = React.toClass(P, React.Component, {
    toggleCondition2: function () {
        this.setState({
            condition2: !this.state.condition2
        });
    },
    toggleCondition1: function () {
        this.setState({
            condition1: !this.state.condition1
        });
    },
    componentDidMount: function () {
        console.log(this.refs.aaa, 'componentDidMount');
    },
    render: function () {
        var h = React.createElement;

        return h('view', { 'class': 'anu-block xxx' },
            h('view', { 'class': 'anu-block' }, h('view', null, 'Condition1 active'),
                h(React.useComponent, { ref: 'aaa', id: 'ybutton', onTap: this.toggleCondition1.bind(this),
                    is: 'YButton', 'data-instance-uid': 'i34_20_' + 0 }, 'Inactive Condition1'),
                h('view', null, 'Condition2 active'),
                h(React.useComponent, { onTap: this.toggleCondition2.bind(this),
                    is: 'YButton', 'data-instance-uid': 'i38_20_' + 0 }, 'Inactive Condition2')));
    },
    classUid: 'c1315'
}, {});
Page(React.registerPage(P, 'pages/demo/syntax/if/index'));

export default P;

通过useComponent这个无状态组件进行引入。 但在无状态组件中不是能使用ref的,因此ref是无法传下去,并且中间多了一个组件,也会导致一部分的fiber的_owner出现错误。 解决办法有两个,1是将useComponent变成有状态组件

var useComponent = miniCreateClass(function useComponent(props) {
  
    this.render = function(){

        var fiber = get(this).return
        while(fiber.return){
            if(fiber.tag < 5){
                get(this)._owner = fiber.stateNode;
              //  console.log(")))))",get(this),  fiber.stateNode)
                break
            }
            fiber = fiber.return
        }
        
        var props = this.props;
        var is = props.is;
        var clazz = registeredComponents[is];//解决import
        props.key = props.key || props['data-instance-uid'] || new Date() - 0;//解决相邻同类型组件数据串了的问题
        delete props.is;
        if (this.ref !== null) {
            props.ref = this.ref;
        }
        var args = [].slice.call(arguments, 2);
        args.unshift(clazz, props);
       return createElement.apply(null,args )    
    }
}, Component);

另一个是

function useComponent(props, context) {
    var is = props.is;
    var clazz = registeredComponents[is];
    props.key = props.key || props['data-instance-uid'] || new Date() - 0;
    delete props.is;
    if (this.ref !== null) {
        props.ref = this.ref;
    }
    var owner = Renderer.currentOwner;
    if(owner){
        Renderer.currentOwner = get(owner)._owner
    }
    return createElement(clazz, props);
}