React函数式组件下父组件调子方法、获取子组件输入值的实现
函数式组件跨父子方法调用落地实现(适配React Native登录场景)
核心实现逻辑
函数式组件场景下实现父组件调用子组件内部方法,完全不需要类组件写法,只需要配合三个React内置能力即可,之前尝试失败大多是漏了React.forwardRef的强制包裹步骤:
- 父组件通过useRef创建引用实例
- 子组件用React.forwardRef包裹,接收父组件传下来的ref参数
- 子组件内部通过useImperativeHandle把需要对外暴露的方法绑定到传入的ref上
子组件改造代码(含输入框+错误提示能力)
import * as React from 'react'; import { TextInput, View, StyleSheet, Text } from 'react-native'; // 重点:必须用forwardRef包裹函数式组件,否则父组件传的ref无法穿透到组件内部 const ChildComponent = React.forwardRef((props, ref) => { const [inputValue, setInputValue] = React.useState(''); const [errorMsg, setErrorMsg] = React.useState(''); // 内部定义的helloWorld方法 function helloWorld() { alert("Hello World"); } // 扩展登录场景需要的错误提示方法 function showError(errorText) { setErrorMsg(errorText); } // 通过useImperativeHandle把需要暴露给父组件的方法挂载到ref上 React.useImperativeHandle(ref, () => ({ helloWorld, showError, getInputValue: () => inputValue })); return ( <View style={styles.inputWrap}> <TextInput style={styles.input} placeholder="尝试从App.js中调用helloWorld方法" value={inputValue} onChangeText={setInputValue} /> {/* 登录校验不通过时展示的红色错误提示 */} {errorMsg ? <Text style={styles.errorTip}>{errorMsg}</Text> : null} </View> ); }); const styles = StyleSheet.create({ inputWrap: { marginBottom: 24, }, input: { borderWidth: 1, borderColor: '#d0d0d0', padding: 12, borderRadius: 4, }, errorTip: { color: 'red', fontSize: 12, marginTop: 4, } }); export default ChildComponent;
父组件App调用代码
import * as React from 'react'; import { Text, View, StyleSheet, TouchableOpacity } from 'react-native'; import Constants from 'expo-constants'; import ChildComponent from './components/ChildComponent'; export default function App() { // 创建ref实例,用于绑定子组件 const childRef = React.useRef(null); function checkSuccess() { // 直接通过ref调用子组件暴露的helloWorld方法 childRef.current?.helloWorld(); // 登录场景下的常见调用示例: // 1. 校验不通过时调用子组件方法展示错误提示 // childRef.current?.showError("账号格式不正确"); // 2. 直接获取子组件输入框的文本值 // const currentInput = childRef.current?.getInputValue(); } return ( <View style={styles.container}> {/* 把ref绑定到ChildComponent标签上 */} <ChildComponent ref={childRef} /> <TouchableOpacity style={styles.button} onPress={checkSuccess} > <Text>调用ChildComponent的helloWorld方法</Text> </TouchableOpacity> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', paddingTop: Constants.statusBarHeight, backgroundColor: '#ecf0f1', padding: 8, }, button: { alignItems: "center", backgroundColor: "#DDDDDD", padding: 10 }, });
之前尝试实现失败的常见踩坑点
- 没有给子组件套React.forwardRef:函数式组件默认不接收ref参数,直接给子组件传ref会被React静默忽略,自然无法拿到内部的方法
- 调用时未做空值判断:组件初始挂载阶段
ref.current为null,直接调用会触发空指针报错,加可选链?.即可规避 - 闭包旧值问题:如果暴露的方法依赖组件内部状态,需要把对应的状态加到useImperativeHandle的第二个参数(依赖数组)中,否则父组件拿到的方法会引用旧的状态值
父组件获取子组件TextInput文本值的两种可选方案
- 方案1:通过useImperativeHandle把取值方法暴露出去,父组件需要时主动调用获取,就是上述代码实现的方式
- 方案2:做状态提升,把输入框的value、onChangeText回调通过props从父组件传入子组件,完全符合React单向数据流的设计范式,适合不需要手动触发子组件方法的场景
内容的提问来源于stack exchange,提问作者Eric
相关产品推荐
相关产品推荐

