日常开发中组件之间的通信是比较经常需要使用到的一点,react的组件数据流方式是从父组件传到子组件,如果子组件需要用到父组件的方法,可以在父组件之间通过props传递,子组件进行调用。但是在业务上有时候无法避免需要用到子组件调用父组件的方法的场景
子组件访问父组件的方法
子组件要访问父组件的方法就比较简单,可以直接通过props来传递父组件的方法,子组件通过props向上调用的方式来访问父组件的函数,直接调用,下面是一些举例的代码。
js
const ParentComponent = () => {
const handleState = (value) => {
}
return (
<ChildComponent getState={handleState}/>
)
}
const ChildComponent = (props) => {
const callMethod = () => {
props.getState('123')
}
return (
<Button onClick={callMethod}>调用父组件方法</Button>
)
}
父组件访问子组件
用下面的方法来获取子组件的方法,创建一个ref,和vue访问子组件的方式类似,都是通过ref的方法
js
import React, { Component } from 'react';
const inputRef = useRef<Input | null>(null);
<div
className={classNames(className, styles.headerSearch)}
onClick={() => {
setSearchMode(true);
if (searchMode && inputRef.current) {
inputRef.current.focus();
}
}}
onTransitionEnd={({ propertyName }) => {
if (propertyName === 'width' && !searchMode) {
if (onVisibleChange) {
onVisibleChange(searchMode);
}
}
}}
>
<Input
size="small"
ref={inputRef}
defaultValue={defaultValue}
aria-label={placeholder}
placeholder={placeholder}
onKeyDown={(e) => {
if (e.key === 'Enter') {
if (restProps.onSearch) {
restProps.onSearch(value);
}
}
}}
onBlur={() => {
setSearchMode(false);
}}
/>
但是上面的方法尝试过后会发现可能存在inputRef.current等于undefined的情况,用起来不是很方便,所以建议尝试下面的方法
useImperativeHandle
useImperativeHandle
是 React 中的一个自定义 Hook,它允许函数式组件与父组件之间的通信。通常情况下,React 的数据流是自上而下的,但有时候需要从子组件向父组件传递数据或方法。useImperativeHandle
就是一个比较方便实现的方法
javascript
javascriptCopy code
import React, { useRef, useImperativeHandle, forwardRef } from 'react';
// 子组件
const ChildComponent = forwardRef((props, ref) => {
const internalRef = useRef();
// 在子组件中定义需要暴露给父组件的方法或数据
useImperativeHandle(ref, () => ({
someFunction: () => {
// 这个函数可以在父组件中被调用
console.log('Function from ChildComponent called');
},
someData: 'Data from ChildComponent',
}));
return (
<div>
{/* 子组件的内容 */}
</div>
);
});
// 父组件
function ParentComponent() {
const childRef = useRef();
const handleButtonClick = () => {
// 在父组件中调用子组件暴露的函数
childRef.current.someFunction();
}
return (
<div>
<ChildComponent ref={childRef} />
<button onClick={handleButtonClick}>Call ChildComponent Function</button>
</div>
);
}
在上面的示例中,useImperativeHandle
用于子组件 ChildComponent
,并通过 forwardRef
使得父组件能够访问 childRef.current
,调用子组件的函数。父组件可以在需要时通过 childRef.current
访问子组件的暴露接口,调用函数或访问数据。
总结
其实react开发中并不赞成去用ref来访问子组件的方法,因为使用ref需要父组件知道子组件内部的解构和方法命名,这样就无法遵从解耦的原则,组件会变得更加的难以重用和维护,并且react推荐组件的独立性和封装性,只通过props来进行通信,直接访问子组件会破坏封装性,导致需要配合父组件来修改子组件
并且组件整个替换或者需要修改内部逻辑的时候,可能需要同时修改子组件和父组件的方法,会大大的增加在开发中的维护复杂度,在开发中应该尽量避免用父组件来访问子组件的方法