0

I have this component in my react js application:

import * as React from "react";
import * as ReactDOM from "react-dom";
import { useForm } from "react-hook-form";

import "./styles.css";

const App = () => {
  const {
    register,
    handleSubmit,
    setValue,
    formState: { errors }
  } = useForm({
    defaultValues: {
      firstName: "",
      lastName: "luo",
      amount: ""
    }
  });

  const onSubmit = (data) => {
    // alert(JSON.stringify(data));
  };

  console.log(JSON.stringify(errors), "f");

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <label>First Name</label>
      <input type="text" {...register("firstName", { required: true })} />
      <input type="submit" />
    </form>
  );
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

When i click on submit i get the next issue: Uncaught TypeError: cyclic object value, this happens because of using JSON stringify.
Question : Why i get this issue in my code and how to use JSON.stringify and to get rid of the issue?
demo: https://codesandbox.io/s/react-hook-form-get-started-ts-forked-wfzjyr?file=/src/index.tsx:0-776

Asking
  • 3,487
  • 11
  • 51
  • 106
  • The `errors` object has a nested `ref` property that points to the HTMLElement object that is invalid. That object has a property `__reactInternalInstance...` that stores an object, which has a property called `stateNode` which points to the same HTMLElement reference, so you have a cycle. Why do you want to check if your object is empty in the first place? Perhaps you can use `Object.getOwnPropertyNames()` and then check the length of the array you get back as an alternative to stringifying, but it's not clear if you actually need to do that depending on what you're trying to do. – Nick Parsons Nov 08 '22 at 11:25

1 Answers1

1

MDN docs explains this error quite well:

The JavaScript exception "cyclic object value" occurs when object references were found in JSON. JSON.stringify() doesn't try to solve them and fails accordingly.

In other words, data has some property that references itself hence a cycle. So turning it into a string naively would result an never ending string. Thus JSON.stringify throws an error if it detects this to be the case.

The docs also outline a good solution but warn that it does cause data loss by ignoring the cyclical value:

const getCircularReplacer = () => {
  const seen = new WeakSet();
  return (key, value) => {
    if (typeof value === "object" && value !== null) {
      if (seen.has(value)) {
        return;
      }
      seen.add(value);
    }
    return value;
  };
};

Then to call it in your code:

JSON.stringify(errors, getCircularReplacer());

From your code, it looks like you think you need to call JSON.stringify in order to use it, e.g. with console.log. This is not necessary for console.log and the console will allow you inspect cyclical objects. This is also true for alert but the output is not useful e.g. [object Object]. However from what I can see, there's no strong reason to use alert over console.log here.

But why even use JSON.stringify if your requirement is to check if it's empty?

From what I can see, when the input field is empty, onSubmit is not called but errors is populated with property firstName. So to check if you have errors for firstName:

Object.hasOwn(error, 'firstName');

See also How do I check if an object has a specific property in JavaScript?

xlm
  • 6,854
  • 14
  • 53
  • 55