Warm tip: This article is reproduced from serverfault.com, please click

React useState hook and submit in multi step form

发布于 2020-11-28 00:10:31

I am creating a multi step form using React JsonSchema Form. I want to update my state every time Next button is clicked on the page and finally Submit. React JsonSchema Form validates the entries only if the button is of type submit. So my Next button is submit button.

As the form will have multiple questions, my state is array of objects. Because of the asynchronous nature of useState, my updated state values are not readily available to save to the backend. How should I get final values?

When I debug I can see the data till previous step. Is there a way to make useState to behave like synchronous call?

Here is the full code:

const data = [
  {
    page: {
      id: 1,
      title: "First Page",
      schema: {
        title: "Todo 1",
        type: "object",
        required: ["title1"],
        properties: {
          title1: { type: "string", title: "Title", default: "A new task" },
          done1: { type: "boolean", title: "Done?", default: false },
        },
      },
    },
  },
  {
    page: {
      id: 1,
      title: "Second Page",
      schema: {
        title: "Todo 2",
        type: "object",
        required: ["title2"],
        properties: {
          title2: { type: "string", title: "Title", default: "A new task" },
          done2: { type: "boolean", title: "Done?", default: false },
        },
      },
    },
  },
];

interface IData {
  id: Number;
  data: any
};

export const Questions: React.FunctionComponent = (props: any) => {

  const [currentPage, setCurrentPage] = useState(0);
  const [surveyData, setSurveyData] = useState<IData[]>([]);

  const handleNext = (e: any) => {
    setSurveyData( previous => [
      ...previous,
      {
        id: currentPage,
        data: e.formData,
      },
    ]);

    if (currentPage < data.length) setCurrentPage(currentPage + 1);
    else //Here I want to submit the data
  };

  const handlePrev = () => {
    setCurrentPage(currentPage - 1);
  };

  return (
      <Form
        schema={data[currentPage].page.schema as JSONSchema7}
        onSubmit={handleNext}
      >
        <Button variant="contained" onClick={handlePrev}>
          Prev
        </Button>
        <Button type="submit" variant="contained">
          Next
        </Button>
      </Form>
 );
};
Questioner
user1868744
Viewed
0
lawrence-witt 2020-11-28 08:24:49

I would refactor the new state structure to use the actual value of the state and not the callback value, since this will allow you to access the whole structure after setting:

  const handleNext = (e: any) => {
    const newSurveyData = [
        ...surveyData,
        {
            id: currentPage,
            data: e.formData
        }
    ];

    setSurveryData(newSurveyData);

    if (currentPage < data.length) {
        setCurrentPage(currentPage + 1);
    } else {
        // submit newSurveryData
    };
  };

A side note: you'll also have to account for the fact that going back a page means you have to splice the new survey data by index rather than just appending it on the end each time.