React中如何从其他组件调用指定组件内的函数?以调用Input校验方法为例
React跨组件调用子组件函数的需求与场景
现有组件结构

Input组件代码
Input组件内部有validate校验函数,在输入框onChange事件触发时自动调用:
import React, {FC, useState} from 'react'; interface InputProps { config : {} } /** * @param config * @constructor */ const Input: FC<InputProps> = ({config}) => { /** * @param inputValue */ const validate: Function = (inputValue: any) => { // Does input validation } return( <div> <input onChange={(event) => { validate(event.target.value); }} /> </div> ); } export default Input;
App.tsx现有代码
需要在点击Button的onClick事件中,同时调用邮箱、密码两个Input组件的validate方法完成全量校验:
import React, {useState} from "react"; import Form from './components/Form/Form'; import Input from './components/UI/Input/Input'; import Button from './components/UI/Button/Button'; const App = () => { return( <div className="app"> <Form title="Simple form"> <Input label="Email address"/> <Input label="Password"/> <Button config={{ text: 'Sign in', onClick: (event) => { // Here I would like to call the validatе method on the email address and // password inputs, but I don’t know how to do this yet. } }}/> </Form> </div> ); } export default App;
实现方案
使用React官方提供的forwardRef+useImperativeHandle组合即可实现父组件调用子组件内部方法,改动如下:
1. 改造Input组件,对外暴露validate方法
import React, {FC, useState, useImperativeHandle, forwardRef} from 'react'; interface InputProps { config ?: {} label: string } // 定义对外暴露的方法类型 export interface InputExpose { validate: () => boolean } const Input = forwardRef<InputExpose, InputProps>(({config, label}, ref) => { // 内部维护输入框的值,方便提交时直接取数校验 const [inputValue, setInputValue] = useState('') const validate = () => { // 可根据label区分字段类型,写对应校验逻辑 if (label === 'Email address') { return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(inputValue) } if (label === 'Password') { return inputValue.length >= 6 } return true } // 自定义对外暴露的属性和方法 useImperativeHandle(ref, () => ({ validate })) return( <div> <input value={inputValue} onChange={(event) => { setInputValue(event.target.value) validate(); }} /> </div> ); }) export default Input;
2. 在App组件中绑定ref,点击按钮时调用校验
import React, {useRef} from "react"; import Form from './components/Form/Form'; import Input, {InputExpose} from './components/UI/Input/Input'; import Button from './components/UI/Button/Button'; const App = () => { // 为两个Input分别创建ref const emailInputRef = useRef<InputExpose>(null) const pwdInputRef = useRef<InputExpose>(null) return( <div className="app"> <Form title="Simple form"> <Input ref={emailInputRef} label="Email address"/> <Input ref={pwdInputRef} label="Password"/> <Button config={{ text: 'Sign in', onClick: () => { // 调用两个子组件的校验方法,统一判断结果 const isEmailValid = emailInputRef.current?.validate() ?? false const isPwdValid = pwdInputRef.current?.validate() ?? false if (isEmailValid && isPwdValid) { // 校验通过,走后续登录逻辑 console.log('表单校验通过') } } }}/> </Form> </div> ); } export default App;
扩展说明
如果后续表单字段较多,可以用ref数组统一管理所有输入框的ref,遍历即可完成批量校验,无需单个声明。
内容的提问来源于stack exchange,提问作者фuɔumж εvоıqжʎuɯɹфʚd
相关产品推荐
相关产品推荐

