[英]How can I expose functions to the ref using functional components?
I want to create a component lets say a calendar functional component which can expose some functions like nextMonth
, prevMonth
, etc. So that the parent component using it can access these functions using the ref
.我想创建一个组件,比如说一个日历功能组件,它可以公开一些函数,如
nextMonth
、 prevMonth
等。这样使用它的父组件就可以使用ref
访问这些函数。 It was easy with class components as the instance methods are automatically exposed.使用类组件很容易,因为实例方法是自动公开的。 How do I achieve the same with functional components?
如何使用功能组件实现相同的功能? I know I can use render props pattern for this.
我知道我可以为此使用渲染道具模式。 But any other solution?
但是还有其他解决方案吗?
Rough example:粗略的例子:
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>
</>
)
}
You can use useImperativeHandle hook.您可以使用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>
)
}
Here's how you can do it, even though it's not really the React way.这是你可以做到的方法,即使它不是真正的 React 方式。 The trick is to set the current value of the
ref
in Calendar
.诀窍是在
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>
)
}
in functional components you can use forwardRef to pass ref to child component.在功能组件中,您可以使用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>
</>
);
}
this work:这项工作:
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>
</>
);
}
While @Matthieu Libeer answer is correct and this should work to you still consider making that in React way.虽然@Matthieu Libeer 的答案是正确的,这应该对您有用,但您仍然可以考虑以 React 的方式进行。 By now your
Calendar
is the same uncontrolled component .到目前为止,您的
Calendar
是相同的不受控制的组件。 By accessing it's internal state(and methods in case of class-based components) by ref you are loosing:通过 ref 访问它的内部状态(以及基于类的组件的方法),您将失去:
Once it would be fully controllable component + keeping consistency with native controls in props' names you would get something like一旦它成为完全可控的组件+与道具名称中的本机控件保持一致,你会得到类似的东西
<Calendar value={currentData} onChange={this.validateAndSetDate} />
This way it can be easily replaced with compatible component(say <input type="date" />
) as well as validation is much more easier.通过这种方式,它可以很容易地替换为兼容的组件(比如
<input type="date" />
)并且验证更容易。 You still might need forwardRef
say to .focus()
imperatively but there will be less pain with other aspects.你仍然可能需要
forwardRef
命令性地对.focus()
说,但其他方面的痛苦会更少。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.