@@ -332,6 +332,88 @@ describe("recommended rules on real-world code", () => {
332332 };
333333 ` ,
334334 } ,
335+ {
336+ // https://github.com/NickvanDyke/eslint-plugin-react-you-might-not-need-an-effect/issues/49
337+ name : "Effect with recursion" , // Particularly likely for `no-manage-parent` because it checks *all* refs in the effect
338+ code : js `
339+ function Component() {
340+ useEffect(() => {
341+ const container = ctnDom.current
342+ if (!container) return
343+
344+ // WebGL setup (~30 lines)
345+ const renderer = new Renderer({ alpha: true, premultipliedAlpha: false })
346+ const gl = renderer.gl
347+ const program = new Program(gl, {
348+ vertex: vert,
349+ fragment: frag,
350+ uniforms: {
351+ iTime: { value: 0 },
352+ iResolution: { value: new Vec3(gl.canvas.width, gl.canvas.height, gl.canvas.width / gl.canvas.height) },
353+ hue: { value: hue },
354+ hover: { value: 0 },
355+ rot: { value: 0 },
356+ hoverIntensity: { value: hoverIntensity },
357+ },
358+ })
359+ const mesh = new Mesh(gl, { geometry, program })
360+
361+ // Nested function 4: animation loop with recursion
362+ let rafId
363+ let lastTime = 0
364+ let currentRot = 0
365+ const rotationSpeed = 0.3
366+
367+ const update = (t) => {
368+ rafId = requestAnimationFrame(update) // Recursive call
369+ const dt = (t - lastTime) * 0.001
370+ lastTime = t
371+ const currentTime = t * 0.001
372+ program.uniforms.iTime.value = currentTime
373+
374+ // Color cycle
375+ if (cycleHue) {
376+ const cyclicHue = (hue + currentTime * hueCycleSpeed) % 360
377+ program.uniforms.hue.value = cyclicHue
378+ } else {
379+ program.uniforms.hue.value = hue
380+ }
381+
382+ program.uniforms.hoverIntensity.value = hoverIntensity
383+
384+ const effectiveHover = forceHoverState ? 1 : targetHover
385+ program.uniforms.hover.value += (effectiveHover - program.uniforms.hover.value) * 0.1
386+
387+ if (rotateOnHover && effectiveHover > 0.5) {
388+ currentRot += dt * rotationSpeed
389+ }
390+ program.uniforms.rot.value = currentRot
391+
392+ renderer.render({ scene: mesh })
393+ }
394+ rafId = requestAnimationFrame(update)
395+
396+ // Cleanup function
397+ return () => {
398+ cancelAnimationFrame(rafId)
399+ window.removeEventListener("resize", resize)
400+ container.removeEventListener("mousemove", handleMouseMove)
401+ container.removeEventListener("mouseleave", handleMouseLeave)
402+ container.removeChild(gl.canvas)
403+ gl.getExtension("WEBGL_lose_context")?.loseContext()
404+ }
405+ }, [
406+ hue,
407+ hoverIntensity,
408+ rotateOnHover,
409+ forceHoverState,
410+ cycleHue,
411+ hueCycleSpeed,
412+ size,
413+ ])
414+ }
415+ ` ,
416+ } ,
335417 ] . forEach ( ( { name, code } ) => {
336418 it ( name , async ( ) => {
337419 const results = await eslint . lintText ( code ) ;
0 commit comments