admin管理员组

文章数量:1401143

First of all here is my code in react

import { useFormState, useFormStatus } from 'react-dom'
import { submitAction } from './action.ts'

export default function Calculator() {
  const [result, submitAction] = useFormState(submitForm, null)

  return (
   <>
    <form action={submitAction}>
      [input fields]

      <button type="reset">
        Reset
      </button>
      <CalculateButton />
    </form>

    <Table headers={inputsCols}>
        {result ? (
          Object.entries(result).map(([rowKey, rowData], rowIndex) => (
            <TableRow key={rowIndex}>
              <TableCell key={rowKey} className="font-bold">
                {rowKey}
              </TableCell>

              {Object.entries(rowData).map(([dataKey, dataValue]) => (
                <TableCell key={`${rowKey}-${dataKey}`}>{dataValue}</TableCell>
              ))}
            </TableRow>
          ))
        ) : (
          <TableRow>
            <TableCell colSpan={inputsCols.length}>No data available</TableCell>
          </TableRow>
        )}
      </Table>
    </>
  )
}

function CalculateButton() {
  const { pending } = useFormStatus()

  return (
    <Button
      type="submit"
      color="orange"
      disabled={pending}
      icon={pending ? LoadingIcon : undefined}
    >
      Calculate
    </Button>
  )
}

I am trying to use reacts server action to submit a form and I want to reset

  1. the form state and
  2. the results returned from the server action

when user clicks the reset button.

the first thing working fine with using button type="reset" inside the form but for the second one I am not quite sure how should I do it.

So, How can I reset the state returned from useFormState in react js? to update the UI so user can enter some other data and do other calculations.

First of all here is my code in react

import { useFormState, useFormStatus } from 'react-dom'
import { submitAction } from './action.ts'

export default function Calculator() {
  const [result, submitAction] = useFormState(submitForm, null)

  return (
   <>
    <form action={submitAction}>
      [input fields]

      <button type="reset">
        Reset
      </button>
      <CalculateButton />
    </form>

    <Table headers={inputsCols}>
        {result ? (
          Object.entries(result).map(([rowKey, rowData], rowIndex) => (
            <TableRow key={rowIndex}>
              <TableCell key={rowKey} className="font-bold">
                {rowKey}
              </TableCell>

              {Object.entries(rowData).map(([dataKey, dataValue]) => (
                <TableCell key={`${rowKey}-${dataKey}`}>{dataValue}</TableCell>
              ))}
            </TableRow>
          ))
        ) : (
          <TableRow>
            <TableCell colSpan={inputsCols.length}>No data available</TableCell>
          </TableRow>
        )}
      </Table>
    </>
  )
}

function CalculateButton() {
  const { pending } = useFormStatus()

  return (
    <Button
      type="submit"
      color="orange"
      disabled={pending}
      icon={pending ? LoadingIcon : undefined}
    >
      Calculate
    </Button>
  )
}

I am trying to use reacts server action to submit a form and I want to reset

  1. the form state and
  2. the results returned from the server action

when user clicks the reset button.

the first thing working fine with using button type="reset" inside the form but for the second one I am not quite sure how should I do it.

So, How can I reset the state returned from useFormState in react js? to update the UI so user can enter some other data and do other calculations.

Share Improve this question edited Jan 15, 2024 at 18:37 Aashutosh Kumar asked Jan 14, 2024 at 18:00 Aashutosh KumarAashutosh Kumar 812 silver badges5 bronze badges 1
  • 1 I like to return a key from my server action, like key: new Date.now(), and then use a useEffect hook. Source: robinwieruch.de/next-forms – Robin Wieruch Commented Mar 18, 2024 at 7:38
Add a ment  | 

2 Answers 2

Reset to default 4

It doesn't appear there is a way to re-initialize the form state from within the ponent rendering the form. You can, however, use a React key to reset the form from outside.

See Resetting a form with a key.

Use some state to represent a "form key" such that you can provide a new React key and effectively remount the Calculator ponent which will have the initial state.

export default function Calculator({ onReset }) {
  const [result, submitAction] = useFormState(submitForm, null)

  return (
   <>
    <form action={submitAction} onReset={onReset}>
      ...input fields...

      <button type="reset">
        Reset
      </button>
      <CalculateButton />
    </form>

    ...
    </>
  )
}
const [formKey, setFormKey] = React.useState(() => nanoid());

const updateFormKey = () => setFormKey(nanoid());
...

<Calculator key={formKey} onReset={updateFormKey} />

Basic Demo

const submitForm = (previousState, formData) => {
  console.log({ previousState });
  return previousState + 1;
};

function Calculator({ onReset }) {
  const [result, submitAction] = ReactDOM.useFormState(submitForm, 0);

  return (
    <React.Fragment>
      <form action={submitAction} onReset={onReset}>
        <div>Result: {result}</div>

        <button type="reset">
          Reset
        </button>
        <CalculateButton />
      </form>
    </React.Fragment>
  );
}

function CalculateButton() {
  const { pending } = ReactDOM.useFormStatus()

  return (
    <button
      type="submit"
      disabled={pending}
    >
      Calculate ({pending ? "loading" : "idle" })
    </button>
  );
}

const App = () => {
  const [formKey, setFormKey] = React.useState(0);

  const updateFormKey = () => setFormKey(key => key + 1);
  return <Calculator key={formKey} onReset={updateFormKey} />;
};

const rootElement = document.getElementById("root");
const root = ReactDOM.createRoot(rootElement);

root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);
<script src="https://cdnjs.cloudflare./ajax/libs/react/18.3.0-canary-cb2439624-20231219/umd/react.development.min.js" integrity="sha512-DyF9mlaay3VPTJNySTYIgb2dsv0NXOcY/IRkCFm/1J/w4B3oOXA6LGwS04cgMFHcSB5b7WXqbOsBaAsWsvcj8g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/react-dom/18.3.0-canary-cb2439624-20231219/umd/react-dom.development.min.js" integrity="sha512-kkJ9iTzcc6cLoFeK+Kp13xvLpIa/+if1NSX7R1ThvHgw6VccDudy8qb5FGyismOvnaGfI604s7ZD6Rzu4Awpng==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<div id="root" />

useFormState is now useActionState (from react core) but the API remains the same.

Here's one possible solution, wrapping the original useActionState to provide a reset function:

import {
  useCallback,
  useState,
  useEffect,
  useRef,
  useActionState as useReactActionState,
} from 'react'

export function useActionState<State, Payload>(
  ...args: Parameters<typeof useReactActionState<State, Payload>>
): [
  ...ReturnType<typeof useReactActionState<State, Payload>>,
  resetActionState: () => void,
] {
  const [state, dispatch, isPending] = useReactActionState(...args)
  const [currentState, setCurrentState] = useState(state)

  const currentStateRef = useRef(currentState)
  currentStateRef.current = currentState

  useEffect(() => {
    if (currentStateRef.current !== state) {
      currentStateRef.current = state
      setCurrentState(state)
    }
  }, [state])

  const [, initialState] = args
  const reset = useCallback(() => {
    currentStateRef.current = initialState
    setCurrentState(initialState)
  }, [initialState])

  return [currentState, dispatch, isPending, reset]
}

Bear in mind that this will introduce an additional render cycle because of the setCurrentState call.

You can use it like so:

const [result, submitAction, , resetFormState] = useActionState(submitForm, null)

// ...
// something happened, reset form state
resetFormState()

本文标签: javascriptHow to reset the state returned from useFormState in react jsStack Overflow