[英]How can I expose functions to the ref using functional components?
我想创建一个组件,比如说一个日历功能组件,它可以公开一些函数,如nextMonth
、 prevMonth
等。这样使用它的父组件就可以使用ref
访问这些函数。 使用类组件很容易,因为实例方法是自动公开的。 如何使用功能组件实现相同的功能? 我知道我可以为此使用渲染道具模式。 但是还有其他解决方案吗?
粗略的例子:
function Calendar() {
const nextMonth = () => {...}
const prevMonth = () => {...}
return (
<div>.....</div>
)
}
function Parent() {
const cal = createRef();
const onNext = () => {
cal.current.nextMonth();
}
return (
<>
<Calendar ref={cal} />
<button onClick={onNext}>Next</button>
</>
)
}
您可以使用useImperativeHandle钩子。
const Calendar = React.forwardRef((props, ref) => {
const [month, setMonth] = useState(0)
const nextMonth = () => { setMonth((prev) => prev + 1) }
const prevMonth = () => { setMonth((prev) => prev - 1) }
useImperativeHandle(ref, () => ({
nextMonth,
prevMonth
}));
return (
<div>{month}</div>
)
})
const Parent = () => {
const cal = useRef()
const onNext = () => {
cal.current.nextMonth()
}
return (
<React.Fragment>
<Calendar ref={cal} />
<button type="button" onClick={onNext}>Next</button>
</React.Fragment>
)
}
这是你可以做到的方法,即使它不是真正的 React 方式。 诀窍是在Calendar
设置ref
的当前值。
const Calendar = React.forwardRef((props, ref) => {
const [month, setMonth] = useState(0)
const nextMonth = () => { setMonth((prev) => prev + 1) }
const prevMonth = () => { setMonth((prev) => prev - 1) }
ref.current = { nextMonth, prevMonth } // eslint-disable-line
return (
<div>{month}</div>
)
})
const Parent = () => {
const cal = useRef()
const onNext = () => {
cal.current.nextMonth()
}
return (
<React.Fragment>
<Calendar ref={cal} />
<button type="button" onClick={onNext}>Next</button>
</React.Fragment>
)
}
在功能组件中,您可以使用forwardRef将 ref 传递给子组件。
const Calendar = React.forwardRef((props, ref) => {
const nextMonth = () => {...};
const prevMonth = () => {...};
return <div>.....</div>;
});
function Parent() {
const cal = useRef(null);
const onNext = () => {
cal.current.nextMonth();
};
return (
<>
<Calendar ref={cal} />
<button onClick={onNext}>Next</button>
</>
);
}
这项工作:
const Calendar = React.forwardRef((props, ref) => {
const nextMonth = () => console.log("nextMonth");
const prevMonth = () => console.log("prevMonth");
ref.current = { nextMonth, prevMonth };
return <div>.....</div>;
});
function Parent() {
const cal = useRef(null);
const onNext = () => {
cal.current.nextMonth();
};
return (
<>
<Calendar ref={cal} />
<button onClick={onNext}>Next</button>
</>
);
}
虽然@Matthieu Libeer 的答案是正确的,这应该对您有用,但您仍然可以考虑以 React 的方式进行。 到目前为止,您的Calendar
是相同的不受控制的组件。 通过 ref 访问它的内部状态(以及基于类的组件的方法),您将失去:
一旦它成为完全可控的组件+与道具名称中的本机控件保持一致,你会得到类似的东西
<Calendar value={currentData} onChange={this.validateAndSetDate} />
通过这种方式,它可以很容易地替换为兼容的组件(比如<input type="date" />
)并且验证更容易。 你仍然可能需要forwardRef
命令性地对.focus()
说,但其他方面的痛苦会更少。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.