Skip to content

regression: formsy's validations prop uses stale values from higher scope (props and state are frozen in the state in which it mounted) #731

@blurymind

Description

@blurymind

I observed this after upgrading from 1.1.4 to 2.3.2

Image

If you try to pass state or props to custom validations functions - they are no longer a reference to the live values but are instead static values of the initial mount.

I made a minimal example here to try
https://codesandbox.io/p/sandbox/2m4j5p

Image

In case you cant open codesandbox

import { useState, useEffect } from "react";
import Formsy, { withFormsy } from "formsy-react";

const Input = ({ errorMessage, value, type, setValue }) => {
  const onChange = (event) => {
    setValue(event.target.value);
  };

  return (
    <div>
      <input onChange={onChange} value={value} type={type} />
      <span>{errorMessage}</span>
    </div>
  );
};
const FormsyInput = withFormsy(Input);
export default function App() {
  const [timer, setTimer] = useState(0);
  const [canSubmit, setCanSubmit] = useState(false);
  const disableButton = () => {
    setCanSubmit(false);
  };

  const enableButton = () => {
    setCanSubmit(true);
  };

  const submit = (model) => {
    fetch("http://example.com/", {
      method: "post",
      body: JSON.stringify(model),
    });
  };

  useEffect(() => {
    setInterval(() => {
      // console.log("timer");
      setTimer((prev) => prev + 0.5);
    }, 1000);
  }, []);

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      <Formsy
        onValidSubmit={submit}
        onValid={enableButton}
        onInvalid={disableButton}
      >
        <FormsyInput
          name="timer"
          validations={{
            isTimer: (values, value) => {
              // BUG - timer no longer updates <-------------------
              console.log({ value, timer });
              // Props or State from a higher scope are frozen in theit value during mount
              return value && value > parseInt(timer);
            },
          }}
          validationErrors={{ isTimer: "Value is lower than timer" }}
          required
          type="number"
        />
        <button type="submit" disabled={!canSubmit}>
          can submit if value is higher than timer
        </button>
      </Formsy>
      {timer}
    </div>
  );
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions