|
9 | 9 |
|
10 | 10 | 'use strict';
|
11 | 11 |
|
12 |
| -let React = require('react'); |
13 |
| -let ReactDOMClient = require('react-dom/client'); |
14 |
| -let act = require('internal-test-utils').act; |
| 12 | +const React = require('react'); |
| 13 | +const ReactDOMClient = require('react-dom/client'); |
| 14 | +const act = require('internal-test-utils').act; |
15 | 15 |
|
16 | 16 | // This is testing if string refs are deleted from `instance.refs`
|
17 | 17 | // Once support for string refs is removed, this test can be removed.
|
18 | 18 | // Detaching is already tested in refs-detruction-test.js
|
19 | 19 | describe('reactiverefs', () => {
|
20 | 20 | let container;
|
21 | 21 |
|
22 |
| - beforeEach(() => { |
23 |
| - jest.resetModules(); |
24 |
| - React = require('react'); |
25 |
| - ReactDOMClient = require('react-dom/client'); |
26 |
| - act = require('internal-test-utils').act; |
27 |
| - }); |
28 |
| - |
29 | 22 | afterEach(() => {
|
30 | 23 | if (container) {
|
31 | 24 | document.body.removeChild(container);
|
@@ -199,11 +192,6 @@ describe('reactiverefs', () => {
|
199 | 192 | describe('ref swapping', () => {
|
200 | 193 | let RefHopsAround;
|
201 | 194 | beforeEach(() => {
|
202 |
| - jest.resetModules(); |
203 |
| - React = require('react'); |
204 |
| - ReactDOMClient = require('react-dom/client'); |
205 |
| - act = require('internal-test-utils').act; |
206 |
| - |
207 | 195 | RefHopsAround = class extends React.Component {
|
208 | 196 | container = null;
|
209 | 197 | state = {count: 0};
|
@@ -804,3 +792,96 @@ describe('refs return clean up function', () => {
|
804 | 792 | expect(nullHandler).toHaveBeenCalledTimes(0);
|
805 | 793 | });
|
806 | 794 | });
|
| 795 | + |
| 796 | +describe('useImerativeHandle refs', () => { |
| 797 | + const ImperativeHandleComponent = React.forwardRef(({name}, ref) => { |
| 798 | + React.useImperativeHandle( |
| 799 | + ref, |
| 800 | + () => ({ |
| 801 | + greet() { |
| 802 | + return `Hello ${name}`; |
| 803 | + }, |
| 804 | + }), |
| 805 | + [name], |
| 806 | + ); |
| 807 | + return null; |
| 808 | + }); |
| 809 | + |
| 810 | + it('should work with object style refs', async () => { |
| 811 | + const container = document.createElement('div'); |
| 812 | + const root = ReactDOMClient.createRoot(container); |
| 813 | + const ref = React.createRef(); |
| 814 | + |
| 815 | + await act(async () => { |
| 816 | + root.render(<ImperativeHandleComponent name="Alice" ref={ref} />); |
| 817 | + }); |
| 818 | + expect(ref.current.greet()).toBe('Hello Alice'); |
| 819 | + await act(() => { |
| 820 | + root.render(null); |
| 821 | + }); |
| 822 | + expect(ref.current).toBe(null); |
| 823 | + }); |
| 824 | + |
| 825 | + it('should work with callback style refs', async () => { |
| 826 | + const container = document.createElement('div'); |
| 827 | + const root = ReactDOMClient.createRoot(container); |
| 828 | + let current = null; |
| 829 | + |
| 830 | + await act(async () => { |
| 831 | + root.render( |
| 832 | + <ImperativeHandleComponent |
| 833 | + name="Alice" |
| 834 | + ref={r => { |
| 835 | + current = r; |
| 836 | + }} |
| 837 | + />, |
| 838 | + ); |
| 839 | + }); |
| 840 | + expect(current.greet()).toBe('Hello Alice'); |
| 841 | + await act(() => { |
| 842 | + root.render(null); |
| 843 | + }); |
| 844 | + expect(current).toBe(null); |
| 845 | + }); |
| 846 | + |
| 847 | + it('should work with callback style refs with cleanup function', async () => { |
| 848 | + const container = document.createElement('div'); |
| 849 | + const root = ReactDOMClient.createRoot(container); |
| 850 | + |
| 851 | + let cleanupCalls = 0; |
| 852 | + let createCalls = 0; |
| 853 | + let current = null; |
| 854 | + |
| 855 | + const ref = r => { |
| 856 | + current = r; |
| 857 | + createCalls++; |
| 858 | + return () => { |
| 859 | + current = null; |
| 860 | + cleanupCalls++; |
| 861 | + }; |
| 862 | + }; |
| 863 | + |
| 864 | + await act(async () => { |
| 865 | + root.render(<ImperativeHandleComponent name="Alice" ref={ref} />); |
| 866 | + }); |
| 867 | + expect(current.greet()).toBe('Hello Alice'); |
| 868 | + expect(createCalls).toBe(1); |
| 869 | + expect(cleanupCalls).toBe(0); |
| 870 | + |
| 871 | + // update a dep should recreate the ref |
| 872 | + await act(async () => { |
| 873 | + root.render(<ImperativeHandleComponent name="Bob" ref={ref} />); |
| 874 | + }); |
| 875 | + expect(current.greet()).toBe('Hello Bob'); |
| 876 | + expect(createCalls).toBe(2); |
| 877 | + expect(cleanupCalls).toBe(1); |
| 878 | + |
| 879 | + // unmounting should call cleanup |
| 880 | + await act(() => { |
| 881 | + root.render(null); |
| 882 | + }); |
| 883 | + expect(current).toBe(null); |
| 884 | + expect(createCalls).toBe(2); |
| 885 | + expect(cleanupCalls).toBe(2); |
| 886 | + }); |
| 887 | +}); |
0 commit comments