Skip to content

[BUG]: Fix circular structure JSON error in RetroEffect implementation with @react-three/postprocessing #163

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
1 task done
Cywinskiweb opened this issue Mar 23, 2025 · 2 comments
Labels
bug Something isn't working

Comments

@Cywinskiweb
Copy link

Describe the issue

Bug Description
When implementing a custom shader effect called RetroEffect with the wrapEffect utility from @react-three/postprocessing, I encountered the following error:

The error occurred with the following code structure:
Uncaught TypeError: Converting circular structure to JSON: --> starting at object with constructor 'Object' | property '_owner' -> object with constructor 'FiberNode' | property 'stateNode' -> object with constructor 'RetroEffect' --- property '_reactInternals' closes the circle

The error occurred specifically when trying to pass props to a component created via wrapEffect:
`
// Original problematic code
import { EffectComposer, wrapEffect } from "@react-three/postprocessing";

const RetroEffect = wrapEffect(
RetroEffectImpl
) as React.ForwardRefExoticComponent<React.RefAttributes>;

// Later in the render:



`

Tech Stack

  • React 19.0.0
  • TypeScript 5.2.2
  • Three.js 0.174.0
  • @react-three/fiber 9.1.0
  • @react-three/postprocessing 3.0.4
  • postprocessing 6.37.1
  • Vite 5.0.8
  • react-router-dom 6.30.0
  • tailwindcss 4.0.15
  • @tailwindcss/vite 4.0.15

Root Cause
The issue is caused by how wrapEffect creates components that can produce circular references when used with certain props. When React tries to validate or process props containing circular references, it attempts to serialize them using JSON.stringify(), which fails with the "Converting circular structure to JSON" error.

My Solution
Instead of using wrapEffect, custom effects should be exposed as primitives using the recommended pattern from the React Postprocessing documentation:

`
// Before - Problematic approach
const RetroEffect = wrapEffect(
RetroEffectImpl
) as React.ForwardRefExoticComponent<React.RefAttributes>;

// After - Fixed approach using primitives
const RetroEffect = forwardRef<RetroEffectImpl, {}>(function RetroEffect(_, ref) {
const effect = useMemo(() => new RetroEffectImpl(), []);
return ;
});
`

// Usage remains the same: <EffectComposer> <RetroEffect ref={effect} /> </EffectComposer>

The RetroEffectImpl class extends the Effect class from the postprocessing library:
class RetroEffectImpl extends Effect { public uniforms: Map<string, THREE.Uniform<any>>; constructor() { const uniforms = new Map<string, THREE.Uniform<any>>([ ["colorNum", new THREE.Uniform(4.0)], ["pixelSize", new THREE.Uniform(2.0)], ]); super("RetroEffect", ditherFragmentShader, { uniforms }); this.uniforms = uniforms; } // Getters and setters for the uniforms // ... }
By using the primitive-based approach, we can still access and modify the effect's properties through the ref, but we avoid the circular reference issue that occurs with the wrapEffect utility.

References
React Postprocessing Custom Effects Documentation
https://react-postprocessing.docs.pmnd.rs/effects/custom-effects

Related issue with circular JSON errors in React: facebook/prop-types#383
https://github.com/facebook/prop-types/issues/383

Three.js discussion on handling circular references: Issue #18934
https://github.com/mrdoob/three.js/issues/18934

Reproduction Link

No response

Steps to reproduce

After setting environment:

  • React 19.0.0
  • TypeScript 5.2.2
  • Three.js 0.174.0
  • @react-three/fiber 9.1.0
  • @react-three/postprocessing 3.0.4
  • postprocessing 6.37.1
  • Vite 5.0.8
  • react-router-dom 6.30.0
  • tailwindcss 4.0.15
  • @tailwindcss/vite 4.0.15

copy / paste Dither tailwind + ts code into new .tsx component then use it in some page (wrapped in react-router-dom 6.30.0). Done.

Validations

  • I have checked other issues to see if my issue was already reported or addressed
@Cywinskiweb Cywinskiweb added the bug Something isn't working label Mar 23, 2025
@DavidHDev
Copy link
Owner

Component is not compatible with React 19

@DavidHDev DavidHDev closed this as not planned Won't fix, can't repro, duplicate, stale Apr 3, 2025
@migueelss
Copy link

Same problem on React 18!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants