form icon indicating copy to clipboard operation
form copied to clipboard

'Cannot convert undefined or null to object' when rendering field conditionally with React.StrictMode

Open Hatzl opened this issue 1 year ago • 4 comments

Describe the bug

If you conditionally render a field with React.StrictMode activated, the library crashes. When disabling React.StrictMode, everything works fine.

Your minimal, reproducible example

https://codesandbox.io/p/devbox/tanstack-form-conditional-field-kfljkr

Steps to reproduce

  1. Click "Submit" - You will get a error "A first name is required"
  2. Click "Hide field" - This will remove First Name field
  3. Click "Submit" again - The app will crash

Expected behavior

The form should submit without crashing.

How often does this bug happen?

Every time

Screenshots or Videos

No response

Platform

OS: MacOS Browser: Chrome

Tanstack Form adapter

react-form

TanStack Form version

v0.13.3

TypeScript version

v5.2.2

Additional context

No response

Hatzl avatar Jan 12 '24 15:01 Hatzl

Wow! Great catch - we'll tackle this ASAP

crutchcorn avatar Jan 12 '24 17:01 crutchcorn

Yes, it took some time to find the problem 😀 Thank you for your support!

Hatzl avatar Jan 19 '24 09:01 Hatzl

I think it has something to do with issue #495 . The crash point is also state.meta.errors = Object.values(state.meta.errorMap).filter( (val) => val !== void 0 ); because errorMap is not defined.

Hatzl avatar Jan 19 '24 09:01 Hatzl

[!NOTE] Edit: You don't have to read this long comment, I created a draft PR with a non-prod-ready solution to illustrate my point (I also explain my thoughts better there): https://github.com/TanStack/form/pull/576

Original comment:

I don't know if I add anything valuable here, but to me, it looks like a new field instance (in form.getFieldInfo('firstName').instances) is created every time the firstName field is rendered, but deleted only every second time it's destroyed. I suspect that this is because the 1st runs are always triggered by <StrictMode> and there's a piece of logic in the useIsomorphicEffectOnce() hook, that prevents the cleanup function from being executed for "dummy React cycles" (this hook is used in useField()):

I think this is what leads to the number of Error messages growing every time we toggle the visibility of the firstName field in the CodeSandbox from the description:

https://github.com/TanStack/form/assets/43729152/ba3523ce-c79e-4cbb-ae18-8d38cb31bb63

Locally I tried to remove the redundant field instances manually in the packages/form-core/src/FieldApi.ts file (lines 402-414), and it seemed to solve the issue, so I could be on the right track here:

    return () => {
      const preserveValue = this.options.preserveValue
      unsubscribe()
      if (!preserveValue) {
        delete info.instances[this.uid - 1] <-- this is the new line (NOT a real solution)
        delete info.instances[this.uid]
        this.form.deleteField(this.name)
      }


      if (!Object.keys(info.instances).length && !preserveValue) {
        delete this.form.fieldInfo[this.name]
      }
    }

https://github.com/TanStack/form/assets/43729152/427b2acf-05e3-4b7a-a302-b6b7f5cf6c3c

Honestly, I'm still very new to the internals of tanstack/form, so I'm just relying on my instincts here... @crutchcorn Does this make any sense? If yes, should I pick it up?

fulopkovacs avatar Jan 21 '24 22:01 fulopkovacs

This required a lot of investigation and internal discussion - thanks for your patience everyone!

Should now be fixed in TanStack Form 0.13.7 🎉

crutchcorn avatar Mar 04 '24 23:03 crutchcorn