# Unlocking the Power of Actions in React 19: Simplifying State Management

%%[kempo] 

React 19 makes it way easier to manage state and data mutations! This is made possible with the introduction of "Actions" which are functions that use async [Transitions](https://react.dev/reference/react/useTransition).

## Actions Reduce Boilerplate

Actions let us skip the manual process of handling pending states, errors, and optimistic updates. If you pass an async function to a transition, React can take over and manage all of this for you.

The easiest way to do this in a component is with the `useTransition` hook:

<iframe src="https://kempo.io/view/eyJpZCI6ImtsX3Vvd2YxdXc3aDdqZmk0Y2pxNWlhcXBqZCIsIm5hbWUiOiJSZWFjdCAxOSBFeGFtcGxlcyIsImNvcmUiOnsiZmlsZXMiOnsiL3N0eWxlcy5jc3MiOnsiY29kZSI6ImJvZHkge1xuICBmb250LWZhbWlseTogc2Fucy1zZXJpZjtcbiAgLXdlYmtpdC1mb250LXNtb290aGluZzogYXV0bztcbiAgLW1vei1mb250LXNtb290aGluZzogYXV0bztcbiAgLW1vei1vc3gtZm9udC1zbW9vdGhpbmc6IGdyYXlzY2FsZTtcbiAgZm9udC1zbW9vdGhpbmc6IGF1dG87XG4gIHRleHQtcmVuZGVyaW5nOiBvcHRpbWl6ZUxlZ2liaWxpdHk7XG4gIGZvbnQtc21vb3RoOiBhbHdheXM7XG4gIC13ZWJraXQtdGFwLWhpZ2hsaWdodC1jb2xvcjogdHJhbnNwYXJlbnQ7XG4gIC13ZWJraXQtdG91Y2gtY2FsbG91dDogbm9uZTtcbiAgcGFkZGluZzogMnJlbTtcbn1cblxuaDEge1xuICBmb250LXNpemU6IDEuNXJlbTtcbn1cblxuLnBvc3RzLXdyYXBwZXIge1xuICBkaXNwbGF5OiBmbGV4O1xuICBmbGV4LWRpcmVjdGlvbjogY29sdW1uO1xuICBnYXA6IDFyZW07XG59XG5cbi5wb3N0cy13cmFwcGVyIGRpdiB7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGFsaWduLWl0ZW1zOiBiYXNlbGluZTtcbiAganVzdGlmeS1jb250ZW50OiBzcGFjZS1iZXR3ZWVuO1xufVxuIn0sIi90c2NvbmZpZy5qc29uIjp7ImNvZGUiOiJ7XG4gIFwiaW5jbHVkZVwiOiBbXG4gICAgXCIuLyoqLypcIlxuICBdLFxuICBcImNvbXBpbGVyT3B0aW9uc1wiOiB7XG4gICAgXCJzdHJpY3RcIjogdHJ1ZSxcbiAgICBcImVzTW9kdWxlSW50ZXJvcFwiOiB0cnVlLFxuICAgIFwibGliXCI6IFsgXCJkb21cIiwgXCJlczIwMTVcIiBdLFxuICAgIFwianN4XCI6IFwicmVhY3QtanN4XCJcbiAgfVxufSJ9LCIvQXBwLnRzeCI6eyJjb2RlIjoiaW1wb3J0IHsgdXNlU3RhdGUsIHVzZVRyYW5zaXRpb24gfSBmcm9tIFwicmVhY3RcIjtcbmltcG9ydCB7IGNyZWF0ZVBvc3QsIFBvc3RzIH0gZnJvbSBcIi4vdXRpbHNcIjtcblxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gQXBwKCk6IEpTWC5FbGVtZW50IHtcbiAgY29uc3QgW3Bvc3RzLCBzZXRQb3N0c10gPSB1c2VTdGF0ZShbXSk7XG4gIGNvbnN0IFtpc1BlbmRpbmcsIHN0YXJ0VHJhbnNpdGlvbl0gPSB1c2VUcmFuc2l0aW9uKCk7XG5cbiAgcmV0dXJuIChcbiAgICA8PlxuICAgICAgPGJ1dHRvblxuICAgICAgICBvbkNsaWNrPXsoKSA9PiB7XG4gICAgICAgICAgc3RhcnRUcmFuc2l0aW9uKGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IG5ld1Bvc3QgPSBhd2FpdCBjcmVhdGVQb3N0KCk7XG4gICAgICAgICAgICBzZXRQb3N0cygocHJldlBvc3RzKSA9PiBbLi4ucHJldlBvc3RzLCBuZXdQb3N0XSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH19XG4gICAgICA+XG4gICAgICAgIEFkZCBQb3N0XG4gICAgICA8L2J1dHRvbj5cbiAgICAgIDxQb3N0cyBwb3N0cz17cG9zdHN9IGlzUGVuZGluZz17aXNQZW5kaW5nfSAvPlxuICAgIDwvPlxuICApO1xufVxuIn0sIi9pbmRleC50c3giOnsiY29kZSI6ImltcG9ydCBSZWFjdCwgeyBTdHJpY3RNb2RlIH0gZnJvbSBcInJlYWN0XCI7XG5pbXBvcnQgeyBjcmVhdGVSb290IH0gZnJvbSBcInJlYWN0LWRvbS9jbGllbnRcIjtcbmltcG9ydCBcIi4vc3R5bGVzLmNzc1wiO1xuXG5pbXBvcnQgQXBwIGZyb20gXCIuL0FwcFwiO1xuXG5jb25zdCByb290ID0gY3JlYXRlUm9vdChkb2N1bWVudC5nZXRFbGVtZW50QnlJZChcInJvb3RcIikpO1xucm9vdC5yZW5kZXIoXG4gIDxTdHJpY3RNb2RlPlxuICAgIDxBcHAgLz5cbiAgPC9TdHJpY3RNb2RlPixcbik7XG4ifSwiL3B1YmxpYy9pbmRleC5odG1sIjp7ImNvZGUiOiI8IURPQ1RZUEUgaHRtbD5cbjxodG1sIGxhbmc9XCJlblwiPlxuICA8aGVhZD5cbiAgICA8bWV0YSBjaGFyc2V0PVwiVVRGLThcIj5cbiAgICA8bWV0YSBuYW1lPVwidmlld3BvcnRcIiBjb250ZW50PVwid2lkdGg9ZGV2aWNlLXdpZHRoLCBpbml0aWFsLXNjYWxlPTEuMFwiPlxuICAgIDx0aXRsZT5Eb2N1bWVudDwvdGl0bGU+XG4gIDwvaGVhZD5cbiAgPGJvZHk+XG4gICAgPGRpdiBpZD1cInJvb3RcIj48L2Rpdj5cbiAgPC9ib2R5PlxuPC9odG1sPiJ9LCIvcGFja2FnZS5qc29uIjp7ImNvZGUiOiJ7XG4gIFwiZGVwZW5kZW5jaWVzXCI6IHtcbiAgICBcInJlYWN0XCI6IFwiMTkuMC4wLWJldGEtMjZmMjQ5NjA5My0yMDI0MDUxNFwiLFxuICAgIFwicmVhY3QtZG9tXCI6IFwiMTkuMC4wLWJldGEtMjZmMjQ5NjA5My0yMDI0MDUxNFwiLFxuICAgIFwicmVhY3Qtc2NyaXB0c1wiOiBcIl40LjAuMFwiXG4gIH0sXG4gIFwiZGV2RGVwZW5kZW5jaWVzXCI6IHtcbiAgICBcIkB0eXBlcy9yZWFjdFwiOiBcIl4xOC4wLjBcIixcbiAgICBcIkB0eXBlcy9yZWFjdC1kb21cIjogXCJeMTguMC4wXCIsXG4gICAgXCJ0eXBlc2NyaXB0XCI6IFwiXjQuMC4wXCJcbiAgfSxcbiAgXCJtYWluXCI6IFwiL2luZGV4LnRzeFwiXG59In0sIi91dGlscy50c3giOnsiY29kZSI6ImFzeW5jIGZ1bmN0aW9uIHNsZWVwKHRpbWVvdXQ6IG51bWJlcikge1xuICByZXR1cm4gYXdhaXQgbmV3IFByb21pc2UoKHIpID0+IHNldFRpbWVvdXQociwgdGltZW91dCkpO1xufVxuXG5sZXQgcG9zdCA9IDE7XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjcmVhdGVQb3N0KCkge1xuICBhd2FpdCBzbGVlcCgxMDAwKTtcbiAgcmV0dXJuIHsgaWQ6IHBvc3QsIHRpdGxlOiBgUG9zdCAke3Bvc3QrK31gIH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBQb3N0cyh7IHBvc3RzLCBpc1BlbmRpbmcgfSkge1xuICByZXR1cm4gKFxuICAgIDxkaXYgY2xhc3NOYW1lPVwicG9zdHMtd3JhcHBlclwiPlxuICAgICAgPGRpdj5cbiAgICAgICAgPGgxPlBvc3RzPC9oMT5cbiAgICAgICAge2lzUGVuZGluZyAmJiA8c3Bhbj5Mb2FkaW5nLi4uPC9zcGFuPn1cbiAgICAgIDwvZGl2PlxuXG4gICAgICB7cG9zdHMubGVuZ3RoID09PSAwICYmIDxwPk5vIFBvc3RzITwvcD59XG5cbiAgICAgIDx1bD5cbiAgICAgICAge3Bvc3RzLm1hcCgocG9zdCkgPT4gKFxuICAgICAgICAgIDxsaSBrZXk9e3Bvc3QuaWR9Pntwb3N0LnRpdGxlfTwvbGk+XG4gICAgICAgICkpfVxuICAgICAgPC91bD5cbiAgICA8L2Rpdj5cbiAgKTtcbn1cbiJ9fSwidGVtcGxhdGUiOiJyZWFjdC10cyJ9LCJkaXNwbGF5Ijp7ImNvbXBvbmVudHMiOnsiRWRpdG9yIjp7InR5cGUiOiJlZGl0b3IiLCJkYXRhIjp7InNob3dUYWJzIjpmYWxzZSwic2hvd0xpbmVOdW1iZXJzIjp0cnVlLCJzaG93SW5saW5lRXJyb3JzIjpmYWxzZSwic2hvd1J1bkJ1dHRvbiI6dHJ1ZSwid3JhcENvbnRlbnQiOnRydWUsImNsb3NhYmxlVGFicyI6ZmFsc2UsInJlYWRPbmx5Ijp0cnVlLCJzaG93UmVhZE9ubHkiOnRydWV9fSwiUHJldmlldyI6eyJ0eXBlIjoicHJldmlldyIsImRhdGEiOnsic2hvd05hdmlnYXRvciI6ZmFsc2UsInNob3dPcGVuSW5Db2RlU2FuZGJveCI6ZmFsc2UsInNob3dSZWZyZXNoQnV0dG9uIjp0cnVlLCJzaG93U2FuZHBhY2tFcnJvck92ZXJsYXkiOmZhbHNlfX19LCJnZW5lcmFsIjp7InZpc2libGVGaWxlcyI6WyIvQXBwLnRzeCJdLCJ0aGVtZSI6ImtlbXBvRGFyayJ9LCJsYXlvdXRzIjp7InNtYWxsIjoiJ0VkaXRvcidcbidFZGl0b3InXG4nUHJldmlldycifX19" height="750px" width="100%"></iframe>

In the example above, notice the `Add Post` button starts a transition when it's clicked which creates a new post. Because this is an asynchronous process, there's a bit of a delay. While the post is being created in the background, the `isPending` variable flips to `true`, which we use to show a loading state.

## Introducing Form Actions

If the changes in the `useTransition` hook weren't cool enough, React 19 also has updates to make it easier to manage forms.

The new `useActionState` and `useFormStatus` hooks make it easier to work with form submissions. In the last example, we had a separate `useState` hook for the `posts` state and a `useTransition` hook to update the `posts` state. With form actions, these two things can be rolled into one:

<iframe src="https://kempo.io/view/eyJpZCI6ImtsX3Vvd2YxdXc3aDdqZmk0Y2pxNWlhcXBqZCIsIm5hbWUiOiJSZWFjdCAxOSBFeGFtcGxlcyIsImNvcmUiOnsiZmlsZXMiOnsiL3N0eWxlcy5jc3MiOnsiY29kZSI6ImJvZHkge1xuICBmb250LWZhbWlseTogc2Fucy1zZXJpZjtcbiAgLXdlYmtpdC1mb250LXNtb290aGluZzogYXV0bztcbiAgLW1vei1mb250LXNtb290aGluZzogYXV0bztcbiAgLW1vei1vc3gtZm9udC1zbW9vdGhpbmc6IGdyYXlzY2FsZTtcbiAgZm9udC1zbW9vdGhpbmc6IGF1dG87XG4gIHRleHQtcmVuZGVyaW5nOiBvcHRpbWl6ZUxlZ2liaWxpdHk7XG4gIGZvbnQtc21vb3RoOiBhbHdheXM7XG4gIC13ZWJraXQtdGFwLWhpZ2hsaWdodC1jb2xvcjogdHJhbnNwYXJlbnQ7XG4gIC13ZWJraXQtdG91Y2gtY2FsbG91dDogbm9uZTtcbiAgcGFkZGluZzogMnJlbTtcbn1cblxuaDEge1xuICBmb250LXNpemU6IDEuNXJlbTtcbn1cblxuZm9ybSB7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGdhcDogMC41cmVtO1xufVxuXG5mb3JtIGJ1dHRvbiB7XG4gIGFsaWduLXNlbGY6IGZsZXgtZW5kO1xufVxuXG5sYWJlbCB7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XG4gIGdhcDogMC4xMjVyZW07XG59XG5cbi5wb3N0cy13cmFwcGVyIHtcbiAgZGlzcGxheTogZmxleDtcbiAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcbiAgZ2FwOiAxcmVtO1xufVxuXG4ucG9zdHMtd3JhcHBlciBkaXYge1xuICBkaXNwbGF5OiBmbGV4O1xuICBhbGlnbi1pdGVtczogYmFzZWxpbmU7XG4gIGp1c3RpZnktY29udGVudDogc3BhY2UtYmV0d2Vlbjtcbn1cbiJ9LCIvdHNjb25maWcuanNvbiI6eyJjb2RlIjoie1xuICBcImluY2x1ZGVcIjogW1xuICAgIFwiLi8qKi8qXCJcbiAgXSxcbiAgXCJjb21waWxlck9wdGlvbnNcIjoge1xuICAgIFwic3RyaWN0XCI6IHRydWUsXG4gICAgXCJlc01vZHVsZUludGVyb3BcIjogdHJ1ZSxcbiAgICBcImxpYlwiOiBbIFwiZG9tXCIsIFwiZXMyMDE1XCIgXSxcbiAgICBcImpzeFwiOiBcInJlYWN0LWpzeFwiXG4gIH1cbn0ifSwiL0FwcC50c3giOnsiY29kZSI6ImltcG9ydCB7IHVzZUFjdGlvblN0YXRlIH0gZnJvbSBcInJlYWN0XCI7XG5pbXBvcnQgeyB1c2VGb3JtU3RhdHVzIH0gZnJvbSBcInJlYWN0LWRvbVwiO1xuaW1wb3J0IHsgY3JlYXRlUG9zdCwgUG9zdHMgfSBmcm9tIFwiLi91dGlsc1wiO1xuXG5mdW5jdGlvbiBTdWJtaXRCdXR0b24ocHJvcHMpIHtcbiAgY29uc3QgeyBwZW5kaW5nIH0gPSB1c2VGb3JtU3RhdHVzKCk7XG4gIHJldHVybiAoXG4gICAgPGJ1dHRvbiB0eXBlPVwic3VibWl0XCIgZGlzYWJsZWQ9e3BlbmRpbmd9PlxuICAgICAge3Byb3BzLmNoaWxkcmVufVxuICAgIDwvYnV0dG9uPlxuICApO1xufVxuXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBBcHAoKTogSlNYLkVsZW1lbnQge1xuICBjb25zdCBbcG9zdHMsIHN1Ym1pdEFjdGlvbiwgaXNQZW5kaW5nXSA9IHVzZUFjdGlvblN0YXRlKFxuICAgIGFzeW5jIChwcmV2UG9zdHMsIGZvcm1EYXRhKSA9PiB7XG4gICAgICBjb25zdCBuZXdQb3N0ID0gYXdhaXQgY3JlYXRlUG9zdChmb3JtRGF0YS5nZXQoXCJwb3N0LXRpdGxlXCIpKTtcbiAgICAgIHJldHVybiBbLi4ucHJldlBvc3RzLCBuZXdQb3N0XTtcbiAgICB9LFxuICAgIFtdLFxuICApO1xuXG4gIHJldHVybiAoXG4gICAgPD5cbiAgICAgIDxmb3JtIGFjdGlvbj17c3VibWl0QWN0aW9ufT5cbiAgICAgICAgPGxhYmVsPlxuICAgICAgICAgIDxzcGFuPlBvc3QgVGl0bGU8L3NwYW4+XG4gICAgICAgICAgPGlucHV0IG5hbWU9XCJwb3N0LXRpdGxlXCIgLz5cbiAgICAgICAgPC9sYWJlbD5cbiAgICAgICAgPFN1Ym1pdEJ1dHRvbj5BZGQgUG9zdDwvU3VibWl0QnV0dG9uPlxuICAgICAgPC9mb3JtPlxuXG4gICAgICA8UG9zdHMgcG9zdHM9e3Bvc3RzfSBpc1BlbmRpbmc9e2lzUGVuZGluZ30gLz5cbiAgICA8Lz5cbiAgKTtcbn1cbiJ9LCIvaW5kZXgudHN4Ijp7ImNvZGUiOiJpbXBvcnQgUmVhY3QsIHsgU3RyaWN0TW9kZSB9IGZyb20gXCJyZWFjdFwiO1xuaW1wb3J0IHsgY3JlYXRlUm9vdCB9IGZyb20gXCJyZWFjdC1kb20vY2xpZW50XCI7XG5pbXBvcnQgXCIuL3N0eWxlcy5jc3NcIjtcblxuaW1wb3J0IEFwcCBmcm9tIFwiLi9BcHBcIjtcblxuY29uc3Qgcm9vdCA9IGNyZWF0ZVJvb3QoZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoXCJyb290XCIpKTtcbnJvb3QucmVuZGVyKFxuICA8U3RyaWN0TW9kZT5cbiAgICA8QXBwIC8+XG4gIDwvU3RyaWN0TW9kZT4sXG4pO1xuIn0sIi9wdWJsaWMvaW5kZXguaHRtbCI6eyJjb2RlIjoiPCFET0NUWVBFIGh0bWw+XG48aHRtbCBsYW5nPVwiZW5cIj5cbiAgPGhlYWQ+XG4gICAgPG1ldGEgY2hhcnNldD1cIlVURi04XCI+XG4gICAgPG1ldGEgbmFtZT1cInZpZXdwb3J0XCIgY29udGVudD1cIndpZHRoPWRldmljZS13aWR0aCwgaW5pdGlhbC1zY2FsZT0xLjBcIj5cbiAgICA8dGl0bGU+RG9jdW1lbnQ8L3RpdGxlPlxuICA8L2hlYWQ+XG4gIDxib2R5PlxuICAgIDxkaXYgaWQ9XCJyb290XCI+PC9kaXY+XG4gIDwvYm9keT5cbjwvaHRtbD4ifSwiL3BhY2thZ2UuanNvbiI6eyJjb2RlIjoie1xuICBcImRlcGVuZGVuY2llc1wiOiB7XG4gICAgXCJyZWFjdFwiOiBcIjE5LjAuMC1iZXRhLTI2ZjI0OTYwOTMtMjAyNDA1MTRcIixcbiAgICBcInJlYWN0LWRvbVwiOiBcIjE5LjAuMC1iZXRhLTI2ZjI0OTYwOTMtMjAyNDA1MTRcIixcbiAgICBcInJlYWN0LXNjcmlwdHNcIjogXCJeNC4wLjBcIlxuICB9LFxuICBcImRldkRlcGVuZGVuY2llc1wiOiB7XG4gICAgXCJAdHlwZXMvcmVhY3RcIjogXCJeMTguMC4wXCIsXG4gICAgXCJAdHlwZXMvcmVhY3QtZG9tXCI6IFwiXjE4LjAuMFwiLFxuICAgIFwidHlwZXNjcmlwdFwiOiBcIl40LjAuMFwiXG4gIH0sXG4gIFwibWFpblwiOiBcIi9pbmRleC50c3hcIlxufSJ9LCIvdXRpbHMudHN4Ijp7ImNvZGUiOiJhc3luYyBmdW5jdGlvbiBzbGVlcCh0aW1lb3V0OiBudW1iZXIpIHtcbiAgcmV0dXJuIGF3YWl0IG5ldyBQcm9taXNlKChyKSA9PiBzZXRUaW1lb3V0KHIsIHRpbWVvdXQpKTtcbn1cblxubGV0IHBvc3QgPSAxO1xuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY3JlYXRlUG9zdCh0aXRsZTogc3RyaW5nKSB7XG4gIGF3YWl0IHNsZWVwKDEwMDApO1xuICByZXR1cm4geyBpZDogcG9zdCwgdGl0bGU6IHRpdGxlIHx8IFwiRW1wdHkgUG9zdFwiIH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBQb3N0cyh7IHBvc3RzLCBpc1BlbmRpbmcgfSkge1xuICByZXR1cm4gKFxuICAgIDxkaXYgY2xhc3NOYW1lPVwicG9zdHMtd3JhcHBlclwiPlxuICAgICAgPGRpdj5cbiAgICAgICAgPGgxPlBvc3RzPC9oMT5cbiAgICAgICAge2lzUGVuZGluZyAmJiA8c3Bhbj5Mb2FkaW5nLi4uPC9zcGFuPn1cbiAgICAgIDwvZGl2PlxuXG4gICAgICB7cG9zdHMubGVuZ3RoID09PSAwICYmIDxwPk5vIFBvc3RzITwvcD59XG5cbiAgICAgIDx1bD5cbiAgICAgICAge3Bvc3RzLm1hcCgocG9zdCkgPT4gKFxuICAgICAgICAgIDxsaSBrZXk9e3Bvc3QuaWR9Pntwb3N0LnRpdGxlfTwvbGk+XG4gICAgICAgICkpfVxuICAgICAgPC91bD5cbiAgICA8L2Rpdj5cbiAgKTtcbn1cbiJ9fSwidGVtcGxhdGUiOiJyZWFjdC10cyJ9LCJkaXNwbGF5Ijp7ImNvbXBvbmVudHMiOnsiRWRpdG9yIjp7InR5cGUiOiJlZGl0b3IiLCJkYXRhIjp7InNob3dUYWJzIjpmYWxzZSwic2hvd0xpbmVOdW1iZXJzIjp0cnVlLCJzaG93SW5saW5lRXJyb3JzIjpmYWxzZSwic2hvd1J1bkJ1dHRvbiI6dHJ1ZSwid3JhcENvbnRlbnQiOnRydWUsImNsb3NhYmxlVGFicyI6ZmFsc2UsInJlYWRPbmx5Ijp0cnVlLCJzaG93UmVhZE9ubHkiOnRydWV9fSwiUHJldmlldyI6eyJ0eXBlIjoicHJldmlldyIsImRhdGEiOnsic2hvd05hdmlnYXRvciI6ZmFsc2UsInNob3dPcGVuSW5Db2RlU2FuZGJveCI6ZmFsc2UsInNob3dSZWZyZXNoQnV0dG9uIjp0cnVlLCJzaG93U2FuZHBhY2tFcnJvck92ZXJsYXkiOmZhbHNlfX19LCJnZW5lcmFsIjp7InZpc2libGVGaWxlcyI6WyIvQXBwLnRzeCJdLCJ0aGVtZSI6ImtlbXBvRGFyayJ9LCJsYXlvdXRzIjp7InNtYWxsIjoiJ0VkaXRvcidcbidFZGl0b3InXG4nUHJldmlldycifX19" height="750px" width="100%"></iframe>

Notice that we're passing a function to the form's `action` prop. Normally, this should be a string like `POST`. This might seem a little weird, but it lets us simplify common use cases.

Here's how it works.

The `useActionState` hook takes an "Action" and the initial state. The "Action" is an asynchronous function that takes the previous state and the `formData` and then returns the *next* state.

The `useActionState` hook returns the current state, a function to invoke the action, and an `isPending` state that's `true` when the Action is executing.

What if we want to know a form is submitting somewhere else in the React component tree?

This is where the `useFormStatus` hook comes into play. This works similar to Context values in React. Because the `SubmitButton` is nested inside the `form` element, we can use the hook to get the `pending` state of the Action. In this case, we disable the button while a post is created.

And that's it! A quick look at Actions and Form Actions. Hopefully this helps you take advantage of some really cool features in React 19.
