对自定义组件中的本地访问引用进行反应

React native accessing refs in a custom component

本文关键字:引用 访问 组件 自定义      更新时间:2023-09-26

我有一个自定义的TextInput。当我编辑第一个TextInput并点击键盘上的"下一个"时,我希望它聚焦第二个TextInput。我以前在Stack Overflow中搜索过,似乎我可以使用ref来完成。但是,我不知道如何使用自定义TextInput来做到这一点。

这是我的基本CustomTextInput代码:

let CustomTextInput = React.createClass({
    propTypes: {
        refName: React.PropTypes.string,
        returnKeyType: React.PropTypes.string,
        onSubmitEditing: React.PropTypes.func
    },
    getDefaultProps: function(){
        return {
            refName: "",
            returnKeyType: "default",
            onSubmitEditing: () => {}
        }
    },
    render: function(){
        return(
            <View>
                <TextInput 
                    ref={this.props.refName}
                    returnKeyType={this.props.returnKeyType}
                    onSubmitEditing={this.props.onSubmitEditing}
                />
            </View>
        )
    }
});
module.exports = CustomTextInput

这是我的父类,称之为:

let MyParent = React.createClass({
    render: function(){
        return(
            <View>
                <CustomTextInput
                    refName={'firstNameInput'},
                    returnKeyType={'next'}
                    onSubmitEditing={(event) => { 
                        this.refs.lastNameInput.focus();
                    }}
                />
                <CustomTextInput
                    refName={'lastNameInput'}
                />
            </View>
        )
    }
});

现在,当我按下键盘上的Next时,在选择firstName后,我得到了一个异常:

undefined不是对象(正在评估'_this2.refs.lastNameInput.focus')

我不确定我在那里做错了什么。。感谢您的帮助。:)

让我们从CustomTextInput组件开始。

export default class CustomTextInput extends Component {
componentDidMount() {
    if (this.props.onRef != null) {
        this.props.onRef(this)
    }
}
onSubmitEditing() {
    this.props.onSubmitEditing();
}
focus() {
    this.textInput.focus()
}

render() {
    return (
        <View>
            <View style={this.state.isFocused ? styles.onFocusedStyle : styles.onBlurStyle}>
                <TextInput
                    ref={input => this.textInput = input}
                    onSubmitEditing={this.onSubmitEditing.bind(this)}
                />
            </View>
            <Text style={styles.errorMessageField}>{this.state.errorStatus && this.props.errorMessage}</Text>
        </View>
    );
}}

这里我有一个示例customTextInput。这里需要注意的重要事项是render方法中TextInput视图中的componentDidMount()、focus()方法和ref属性。

  1. componentDidMount()方法将整个CustomTextInput组件的ref传递给其父组件。通过该引用,我们将从父组件调用CustomTextInput组件的焦点方法。

  2. focus()方法通过在CustomTextInput组件内使用textInput组件的ref来将textInput集中在CustomTextInput组件内。

  3. TextInput的ref属性存储TextInput的引用。这个引用由focus()方法使用。

现在让我们看看父组件

export default class ParentComponent extends Component {
constructor(props) {
    super(props);
    this.focusNextField = this.focusNextField.bind(this);
    this.inputs = {};
}

focusNextField(id) {
    this.inputs[id].focus();
}
render() {
    return (
        <ScrollView
            contentContainerStyle={{paddingBottom:100}}
            keyboardDismissMode={'on-drag'}
            scrollToTop={true}>
            <View>
                    <View style={{marginTop: 10}}>
                        <CustomTextInput
                            onRef={(ref) => {
                                this.inputs['projectName'] = ref;
                            }}
                            onSubmitEditing={() => {
                                this.focusNextField('projectDescription');
                            }}
                            />
                    </View>
                    <View style={{marginTop: 10}}>
                        <CustomTextInput
                            onRef={(ref) => {
                                this.inputs['projectDescription'] = ref;
                            }}
                            onSubmitEditing={() => {
                                this.focusNextField('subDivision');
                            }}
                        />
                    </View>
                    <View style={{marginTop: 10}}>
                        <CustomTextInput
                            onRef={(ref) => {
                                this.inputs['subDivision'] = ref;
                            }}
                            onSubmitEditing={() => {
                                this.focusNextField('plan');
                            }}
                           />
                    </View>
                    <View style={{marginTop: 10}}>
                        <CustomTextInput
                            onRef={(ref) => {
                                this.inputs['plan'] = ref;
                            }}
                    </View>
            </View>
        </ScrollView>
    );
}}

在父组件中,我们使用onRef属性存储每个CustomTextInput的ref,当按下键盘上的提交按钮时,我们调用下一个CustomTextInput中的焦点方法,CustomTextInput焦点方法将TextInput集中在子组件中。

这里有一个解决方案,您正在使用功能组件:

您的自定义组件需要使用React.forwardRef

const CustomTextInput = React.forwardRef((props, ref) => {
    return (
        <TextInput
            {...props}
            ref={ref}
        />
    );
});
export default CustomTextInput;

导入自定义组件的父组件:

import React, { createRef } from 'react';
const ParentComponent = () => {
    let customTextInputRef = createRef();
    return (
        <View>
            <CustomTextInput
                onSubmitEditing={() => customTextInputRef.current.focus()}}
            />
            <CustomTextInput
                ref={customTextInputRef}
            />
        </View>
    );
};

这里有一个对我有用的解决方案——基本上,您可以在自定义组件中创建一个引用,您可以从父组件中的引用中访问该引用:

let CustomTextInput = React.createClass({
    propTypes: {
        refName: React.PropTypes.string,
        returnKeyType: React.PropTypes.string,
        onSubmitEditing: React.PropTypes.func
    },
    getDefaultProps: function(){
        return {
            refName: "",
            returnKeyType: "default",
            onSubmitEditing: () => {}
        }
    },
    render: function(){
        return(
            <View>
                <TextInput 
                    ref="input"
                    returnKeyType={this.props.returnKeyType}
                    onSubmitEditing={this.props.onSubmitEditing}
                />
            </View>
        )
    }
});
module.exports = CustomTextInput

在父组件中:

let MyParent = React.createClass({
    render: function(){
        return(
            <View>
                <CustomTextInput
                    refName={'firstNameInput'},
                    returnKeyType={'next'}
                    onSubmitEditing={(event) => { 
                        this.lastNameInput.refs.input.focus();
                    }}
                />
                <CustomTextInput
                    refName={ref => this.lastNameInput = ref}
                />
            </View>
        )
    }
});
let CustomTextInput = React.createClass({
    componentDidMount() {
        // this is to check if a refName prop is FUNCTION; 
        if (typeof this.props.rex === "function") {
            this.props.refName(this.refs.inp);
        }
    }
    render: function() {
        return(
            <View>
                <TextInput ref={"inp"}/>
            </View>
        )
    }
});
let MyParent = React.createClass({
    render: function() {
        return (
            <View>
                <CustomTextInput
                    refName={ (firstNameInput) => this.firstNameInput = firstNameInput }
                />
            </View>
        )
    }
});

试试这个:

let AwesomeProject = React.createClass({
    onSubmitEditing:function(event){
        if (this.myTextInput !== null) {
          this.myTextInput.focus();
        }
    },
    render(){
        return(
            <View>
                <CustomTextInput
                    returnKeyType={'next'}
                    onSubmitEditing={this.onSubmitEditing}
                />
                <CustomTextInput
                    refName={(ref) => this.myTextInput = ref}
                />
            </View>
        )
    }
});