Reputation: 81
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
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.
Upvotes: 8
Views: 5611
Reputation: 7379
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()
Upvotes: 0
Reputation: 203218
It doesn't appear there is a way to re-initialize the form state from within the component 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
component 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} />
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.com/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.com/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" />
Upvotes: 4