From 8c6507fb89887b4802056fa8b50baba7f9d3ae5b Mon Sep 17 00:00:00 2001 From: Morgan Zolob Date: Mon, 9 Dec 2019 22:04:04 -0800 Subject: [PATCH] Fix passing ref to functional components (#153) --- src/index.tsx | 20 +++++++++---- tests/basic.test.jsx | 67 ++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 76 insertions(+), 11 deletions(-) diff --git a/src/index.tsx b/src/index.tsx index d100aa43..21c6c4fb 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,4 +1,4 @@ -import React, { HTMLAttributes } from 'react'; +import React, { HTMLAttributes, RefAttributes, ReactInstance } from 'react'; import ReactDOM from 'react-dom'; import contains from 'rc-util/lib/Dom/contains'; import findDOMNode from 'rc-util/lib/Dom/findDOMNode'; @@ -676,7 +676,8 @@ export function generateTrigger(PortalComponent: any): React.ComponentClass & { key: string } = { key: 'trigger' }; + const newChildProps: HTMLAttributes & + RefAttributes & { key: string } = { key: 'trigger' }; if (this.isContextMenuToShow()) { newChildProps.onContextMenu = this.onContextMenu; @@ -721,10 +722,17 @@ export function generateTrigger(PortalComponent: any): React.ComponentClass { }); it('support function component', () => { - const NoRef = React.forwardRef((props, ref) => { - React.useImperativeHandle(ref, () => null); - return ( + const FuncComp = props => (
click
); - }); const wrapper = mount( { popupAlign={placementAlignMap.left} popup={tooltip2} > - + , ); @@ -539,4 +536,64 @@ describe('Trigger.Basic', () => { wrapper.trigger(); expect(wrapper.isHidden()).toBeTruthy(); }); + + describe('passes ref to children where applicable', () => { + function getRefResult(component) { + const triggerMock = jest.fn(); + const wrapper = mount( + tooltip2} + ref={triggerMock} + > + {component} + , + ); + + wrapper.trigger(); + + return triggerMock.mock.calls[0][0].triggerRef.current; + } + + it('does not pass ref to function component', () => { + const NoRef = props => ( +
+ click +
+ ); + + const refVal = getRefResult(); + expect(refVal).toBeNull(); + }); + + it('does pass ref to forwardRef function component', () => { + const WithRef = React.forwardRef((props, ref) => ( +
+ click +
+ )); + + const refVal = getRefResult(); + expect(refVal.id).toBe('target'); + }); + + it('does pass ref to class component', () => { + class ClassComp extends React.Component { + id = 'target'; + + render() { + return
click
; + } + } + + const refVal = getRefResult(); + expect(refVal.id).toBe('target'); + }); + + it('does pass ref to element', () => { + const refVal = getRefResult(
click
); + expect(refVal.id).toBe('target'); + }); + }); });