最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to reset the state returned from useFormState in react js? - Stack Overflow

programmeradmin6浏览0评论

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()
发布评论

评论列表(0)

  1. 暂无评论