@samitouri / QOS-React / commits / 5135f98795

Add DOM fixture page for Fragment Ref (#32527)

This adds a page to the DOM fixture to test Fragment Refs. The first test case is for `addEventListener`/`removeEventListener`. Setting `enableFragmentRefs` to `__EXPERIMENTAL__` and building is required to run the fixture. <img width="872" alt="Screenshot 2025-03-05 at 12 58 57 PM" src="https://github.com/user-attachments/assets/fee498b7-fd96-4178-9e82-c46d4cb55c9b" />

Jack Pope committed Mar 12, 2025 at 17:49 UTC 5135f98795d13aeea6f009b537a660c7afbe17ed
3 files changed +118
fixtures/dom/src/components/Header.js
+1
@@ -89,6 +89,7 @@ class Header extends React.Component {
89 <option value="/selection-events">Selection Events</option>
90 <option value="/suspense">Suspense</option>
91 <option value="/form-state">Form State</option>
92 + <option value="/fragment-refs">Fragment Refs</option>
93 </select>
94 </label>
95 <label htmlFor="global_version">
fixtures/dom/src/components/fixtures/fragment-refs/index.js new
+104
@@ -0,0 +1,104 @@
1 +import Fixture from '../../Fixture';
2 +import FixtureSet from '../../FixtureSet';
3 +import TestCase from '../../TestCase';
4 +
5 +const React = window.React;
6 +const {Fragment, useEffect, useRef, useState} = React;
7 +
8 +function WrapperComponent(props) {
9 + return props.children;
10 +}
11 +
12 +function handler(e) {
13 + const text = e.currentTarget.innerText;
14 + alert('You clicked: ' + text);
15 +}
16 +
17 +export default function FragmentRefsPage() {
18 + const fragmentRef = useRef(null);
19 + const [extraChildCount, setExtraChildCount] = useState(0);
20 +
21 + React.useEffect(() => {
22 + fragmentRef.current.addEventListener('click', handler);
23 +
24 + const lastFragmentRefValue = fragmentRef.current;
25 + return () => {
26 + lastFragmentRefValue.removeEventListener('click', handler);
27 + };
28 + });
29 +
30 + return (
31 + <FixtureSet title="Fragment Refs">
32 + <TestCase title="Event registration">
33 + <TestCase.Steps>
34 + <li>Click one of the children, observe the alert</li>
35 + <li>Add a new child, click it, observe the alert</li>
36 + <li>Remove the event listeners, click a child, observe no alert</li>
37 + <li>
38 + Add the event listeners back, click a child, observe the alert
39 + </li>
40 + </TestCase.Steps>
41 +
42 + <TestCase.ExpectedResult>
43 + <p>
44 + Fragment refs can manage event listeners on the first level of host
45 + children. This page loads with an effect that sets up click event
46 + hanndlers on each child card. Clicking on a card will show an alert
47 + with the card's text.
48 + </p>
49 + <p>
50 + New child nodes will also have event listeners applied. Removed
51 + nodes will have their listeners cleaned up.
52 + </p>
53 + </TestCase.ExpectedResult>
54 +
55 + <Fixture>
56 + <div className="control-box" id="control-box">
57 + <div>Target count: {extraChildCount + 3}</div>
58 + <button
59 + onClick={() => {
60 + setExtraChildCount(prev => prev + 1);
61 + }}>
62 + Add Child
63 + </button>
64 + <button
65 + onClick={() => {
66 + fragmentRef.current.addEventListener('click', handler);
67 + }}>
68 + Add click event listeners
69 + </button>
70 + <button
71 + onClick={() => {
72 + fragmentRef.current.removeEventListener('click', handler);
73 + }}>
74 + Remove click event listeners
75 + </button>
76 + <div class="card-container">
77 + <Fragment ref={fragmentRef}>
78 + <div className="card" id="child-a">
79 + Child A
80 + </div>
81 + <div className="card" id="child-b">
82 + Child B
83 + </div>
84 + <WrapperComponent>
85 + <div className="card" id="child-c">
86 + Child C
87 + </div>
88 + {Array.from({length: extraChildCount}).map((_, index) => (
89 + <div
90 + className="card"
91 + id={'extra-child-' + index}
92 + key={index}>
93 + Extra Child {index}
94 + </div>
95 + ))}
96 + </WrapperComponent>
97 + </Fragment>
98 + </div>
99 + </div>
100 + </Fixture>
101 + </TestCase>
102 + </FixtureSet>
103 + );
104 +}
fixtures/dom/src/style.css
+13
@@ -309,3 +309,16 @@ th {
309 tbody tr:nth-child(even) {
310 background: #f0f0f0;
311 }
312 +
313 +.card-container {
314 + display: flex;
315 + flex-wrap: wrap;
316 +}
317 +
318 +.card {
319 + background: white;
320 + border-radius: 2px;
321 + border: 1px solid rgba(0, 0, 0, 0.24);
322 + margin: 10px;
323 + padding: 10px;
324 +}