diff --git a/content/blog/what-is-use-form-state-and-status/index.md b/content/blog/what-is-use-form-state-and-status/index.md index bec4bd4e..ebb412e1 100644 --- a/content/blog/what-is-use-form-state-and-status/index.md +++ b/content/blog/what-is-use-form-state-and-status/index.md @@ -294,45 +294,70 @@ Assume you have the above sample code, but you have JavaScript disabled. When yo > Keep in mind that any client-side React code will not run if JavaScript is disabled. This includes the `useEffect` Hook among others. -# Use `useFormState` and `useFormStatus` together +# How to use `useFormState` and `useFormStatus` together + +You may have noticed that `useFormState` doesn't provide us the same pending information that `useFormStatus` does. Let's combine them for the ultimate user experience: ```jsx -function Submit() { - const status = useFormStatus(); - return ( - - ); -} +// page.jsx +import { Todo } from "./client"; +import { addTodoToDatabase, getTodos } from "./todos"; +import { redirect } from "next/navigation"; -function App() { - async function sayHi() { - await new Promise((resolve) => { - setTimeout(() => { - resolve(); - }, 1000); - }); - return 'Value from the action'; - } +export default async function Home() { + const todos = await getTodos(); - const [state, action] = useFormState(sayHi, 'Initial value'); + async function addTodo(previousState, formData) { + "use server"; + const todo = formData.get("todo"); + if (!todo) return "Please enter a todo"; + await addTodoToDatabase(todo); + redirect("/"); + } - return ( -
-

{state}

- - - ); + return ; } ``` -We can even expand this into our real world example: - ```jsx -// TODO: Write real world example +// client.jsx +"use client"; +import { useFormState, useFormStatus } from "react-dom"; + +function TodoFormInner() { + const status = useFormStatus(); + return ( + <> + {status.pending &&

Adding todo...

} + + + + ); +} + +export function Todo({ todos, addTodo }) { + const [state, action] = useFormState(addTodo, ""); + + return ( + <> +
+ {state &&

{state}

} + + +
    + {todos.map((todo) => { + return
  • {todo.value}
  • ; + })} +
+ + ); +} ``` + + # Conclusion // TODO: Write diff --git a/content/blog/what-is-use-form-state-and-status/nextjs-use-form-state-and-status/.gitignore b/content/blog/what-is-use-form-state-and-status/nextjs-use-form-state-and-status/.gitignore new file mode 100644 index 00000000..8f322f0d --- /dev/null +++ b/content/blog/what-is-use-form-state-and-status/nextjs-use-form-state-and-status/.gitignore @@ -0,0 +1,35 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/content/blog/what-is-use-form-state-and-status/nextjs-use-form-state-and-status/app/client.jsx b/content/blog/what-is-use-form-state-and-status/nextjs-use-form-state-and-status/app/client.jsx new file mode 100644 index 00000000..f9960fec --- /dev/null +++ b/content/blog/what-is-use-form-state-and-status/nextjs-use-form-state-and-status/app/client.jsx @@ -0,0 +1,33 @@ +"use client"; +import { useFormState, useFormStatus } from "react-dom"; + +function TodoFormInner() { + const status = useFormStatus(); + return ( + <> + {status.pending &&

Adding todo...

} + + + + ); +} + +export function Todo({ todos, addTodo }) { + const [state, action] = useFormState(addTodo, ""); + + return ( + <> +
+ {state &&

{state}

} + + +
    + {todos.map((todo) => { + return
  • {todo.value}
  • ; + })} +
+ + ); +} diff --git a/content/blog/what-is-use-form-state-and-status/nextjs-use-form-state-and-status/app/layout.jsx b/content/blog/what-is-use-form-state-and-status/nextjs-use-form-state-and-status/app/layout.jsx new file mode 100644 index 00000000..35e62ecc --- /dev/null +++ b/content/blog/what-is-use-form-state-and-status/nextjs-use-form-state-and-status/app/layout.jsx @@ -0,0 +1,13 @@ +export const metadata = { + title: "Next.js useFormState and useFormStatus", + description: + "For use in the Next.js useFormState article on Unicorn Utterances", +}; + +export default function RootLayout({ children }) { + return ( + + {children} + + ); +} diff --git a/content/blog/what-is-use-form-state-and-status/nextjs-use-form-state-and-status/app/page.jsx b/content/blog/what-is-use-form-state-and-status/nextjs-use-form-state-and-status/app/page.jsx new file mode 100644 index 00000000..e8cbba11 --- /dev/null +++ b/content/blog/what-is-use-form-state-and-status/nextjs-use-form-state-and-status/app/page.jsx @@ -0,0 +1,17 @@ +import { Todo } from "./client"; +import { addTodoToDatabase, getTodos } from "./todos"; +import { redirect } from "next/navigation"; + +export default async function Home() { + const todos = await getTodos(); + + async function addTodo(previousState, formData) { + "use server"; + const todo = formData.get("todo"); + if (!todo) return "Please enter a todo"; + await addTodoToDatabase(todo); + redirect("/"); + } + + return ; +} diff --git a/content/blog/what-is-use-form-state-and-status/nextjs-use-form-state-and-status/app/todos.js b/content/blog/what-is-use-form-state-and-status/nextjs-use-form-state-and-status/app/todos.js new file mode 100644 index 00000000..e2d78216 --- /dev/null +++ b/content/blog/what-is-use-form-state-and-status/nextjs-use-form-state-and-status/app/todos.js @@ -0,0 +1,24 @@ +// Pretend this is a real database +let id = 0; +const todos = []; + +function getRandomTimePromise() { + return new Promise((resolve) => { + setTimeout( + () => { + resolve(); + }, + Math.floor(Math.random() * 3000), + ); + }); +} + +export async function addTodoToDatabase(todo) { + await getRandomTimePromise(); + todos.push({ value: todo, id: ++id }); +} + +export async function getTodos() { + await getRandomTimePromise(); + return [...todos]; +} diff --git a/content/blog/what-is-use-form-state-and-status/nextjs-use-form-state-and-status/package-lock.json b/content/blog/what-is-use-form-state-and-status/nextjs-use-form-state-and-status/package-lock.json new file mode 100644 index 00000000..7758c3b4 --- /dev/null +++ b/content/blog/what-is-use-form-state-and-status/nextjs-use-form-state-and-status/package-lock.json @@ -0,0 +1,636 @@ +{ + "name": "@unicorn-utterances/nextjs-use-form-state-and-status", + "version": "0.1.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "@unicorn-utterances/nextjs-use-form-state-and-status", + "version": "0.1.0", + "dependencies": { + "next": "14.0.5-canary.20", + "react": "18.2.0", + "react-dom": "18.2.0", + "typescript": "5.2.2" + } + }, + "node_modules/@next/env": { + "version": "14.0.5-canary.20", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.0.5-canary.20.tgz", + "integrity": "sha512-jmlgC2XjCMb3gsnYse2jLrXD29OSz5XAZYQQyYf5bDCHfz+bhfIcuIwNYV/kT9R4VsxRFIs7jOIy5Fi+rRAhWQ==" + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "14.0.5-canary.20", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.0.5-canary.20.tgz", + "integrity": "sha512-0psWoc4cUM6zbNv7M9/Z+kurjc8TIOaett+rNpZiRLXjIj1mBhLvL4gv7cDclmTdu8c5NdsbcB1n3fTZqkKu5g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "14.0.5-canary.20", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.0.5-canary.20.tgz", + "integrity": "sha512-DQfRLnQ6Ez2EF3meqzeZjuDlUOUBfMWrjTqi5JgvwmqTbKGqpZ7OvouCiyv6hqSHXHdLONI8B1kcl8KHHg7y5g==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "14.0.5-canary.20", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.0.5-canary.20.tgz", + "integrity": "sha512-48VAltdElYVC0Z3NneP8ULmK0bw8XM2XVbTyJOyr7gDv7NIBDJQF7icm07wC7Mu8mPrYPsEI5Rub/ot0MqCRJA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "14.0.5-canary.20", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.0.5-canary.20.tgz", + "integrity": "sha512-zlONL+iNztgAfdff93QwoclpEiS5rg75DcGKTo1ShWcxV3r4WJle787bD859DQ0xO9VOUWqqykuxIZH2qeyJog==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "14.0.5-canary.20", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.0.5-canary.20.tgz", + "integrity": "sha512-T6cOjZ+6me1IawzUtecopl3TkTkg65av2/5Xd8QnAzu7gtUYoAlqIWSoGLDFi/5qjn5h3Oke1pmvaqu8odpHxw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "14.0.5-canary.20", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.0.5-canary.20.tgz", + "integrity": "sha512-Zj6TMPt03YGry9Sd722vMTm58QIC+5sqnjtwoCXApDjdkwYjgx7Y3E4IseIWI+SykpBt8NrlehIiijobX2SFtg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "14.0.5-canary.20", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.0.5-canary.20.tgz", + "integrity": "sha512-s0hESqVwnGZCT9zbnXzrDlBOf6LTBTS5vijWOvJJOjpxNmZptCYPxEgOItuvCAi5NBf9rlSDIQyYOCDBn82HZw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-ia32-msvc": { + "version": "14.0.5-canary.20", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.0.5-canary.20.tgz", + "integrity": "sha512-0J9GWQmX4YuWHwWigY4QVNsMBBUxctAUD/2tjwo6cZYkfPa4Z56vwsN4o3pysdwMXasUvdXtrMo8ANkA9XtWkw==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "14.0.5-canary.20", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.0.5-canary.20.tgz", + "integrity": "sha512-kuFJcBNOvcY4T4xqt2UJIJl5XBD8z4XsciThth7Tq1w6Yq4g+c6LD/Fg9tcHI+XQdlcXtl1mxqYn5rkrRYa3AQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@swc/helpers": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz", + "integrity": "sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001570", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001570.tgz", + "integrity": "sha512-+3e0ASu4sw1SWaoCtvPeyXp+5PsjigkSt8OXZbF9StH5pQWbxEjLAZE3n8Aup5udop1uRiKA7a4utUk/uoSpUw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/next": { + "version": "14.0.5-canary.20", + "resolved": "https://registry.npmjs.org/next/-/next-14.0.5-canary.20.tgz", + "integrity": "sha512-H3X0NQCLnqp6b9xZL0Tx3sgdWwWESlj3Md0AdCHTMdfXCNvTL2r9gjwPXtklAUizCUA22vhrcUJkqralFmmoRA==", + "dependencies": { + "@next/env": "14.0.5-canary.20", + "@swc/helpers": "0.5.2", + "busboy": "1.6.0", + "caniuse-lite": "^1.0.30001406", + "graceful-fs": "^4.2.11", + "postcss": "8.4.31", + "styled-jsx": "5.1.1", + "watchpack": "2.4.0" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": ">=18.17.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "14.0.5-canary.20", + "@next/swc-darwin-x64": "14.0.5-canary.20", + "@next/swc-linux-arm64-gnu": "14.0.5-canary.20", + "@next/swc-linux-arm64-musl": "14.0.5-canary.20", + "@next/swc-linux-x64-gnu": "14.0.5-canary.20", + "@next/swc-linux-x64-musl": "14.0.5-canary.20", + "@next/swc-win32-arm64-msvc": "14.0.5-canary.20", + "@next/swc-win32-ia32-msvc": "14.0.5-canary.20", + "@next/swc-win32-x64-msvc": "14.0.5-canary.20" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/styled-jsx": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", + "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "node_modules/typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + } + }, + "dependencies": { + "@next/env": { + "version": "14.0.5-canary.20", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.0.5-canary.20.tgz", + "integrity": "sha512-jmlgC2XjCMb3gsnYse2jLrXD29OSz5XAZYQQyYf5bDCHfz+bhfIcuIwNYV/kT9R4VsxRFIs7jOIy5Fi+rRAhWQ==" + }, + "@next/swc-darwin-arm64": { + "version": "14.0.5-canary.20", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.0.5-canary.20.tgz", + "integrity": "sha512-0psWoc4cUM6zbNv7M9/Z+kurjc8TIOaett+rNpZiRLXjIj1mBhLvL4gv7cDclmTdu8c5NdsbcB1n3fTZqkKu5g==", + "optional": true + }, + "@next/swc-darwin-x64": { + "version": "14.0.5-canary.20", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.0.5-canary.20.tgz", + "integrity": "sha512-DQfRLnQ6Ez2EF3meqzeZjuDlUOUBfMWrjTqi5JgvwmqTbKGqpZ7OvouCiyv6hqSHXHdLONI8B1kcl8KHHg7y5g==", + "optional": true + }, + "@next/swc-linux-arm64-gnu": { + "version": "14.0.5-canary.20", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.0.5-canary.20.tgz", + "integrity": "sha512-48VAltdElYVC0Z3NneP8ULmK0bw8XM2XVbTyJOyr7gDv7NIBDJQF7icm07wC7Mu8mPrYPsEI5Rub/ot0MqCRJA==", + "optional": true + }, + "@next/swc-linux-arm64-musl": { + "version": "14.0.5-canary.20", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.0.5-canary.20.tgz", + "integrity": "sha512-zlONL+iNztgAfdff93QwoclpEiS5rg75DcGKTo1ShWcxV3r4WJle787bD859DQ0xO9VOUWqqykuxIZH2qeyJog==", + "optional": true + }, + "@next/swc-linux-x64-gnu": { + "version": "14.0.5-canary.20", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.0.5-canary.20.tgz", + "integrity": "sha512-T6cOjZ+6me1IawzUtecopl3TkTkg65av2/5Xd8QnAzu7gtUYoAlqIWSoGLDFi/5qjn5h3Oke1pmvaqu8odpHxw==", + "optional": true + }, + "@next/swc-linux-x64-musl": { + "version": "14.0.5-canary.20", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.0.5-canary.20.tgz", + "integrity": "sha512-Zj6TMPt03YGry9Sd722vMTm58QIC+5sqnjtwoCXApDjdkwYjgx7Y3E4IseIWI+SykpBt8NrlehIiijobX2SFtg==", + "optional": true + }, + "@next/swc-win32-arm64-msvc": { + "version": "14.0.5-canary.20", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.0.5-canary.20.tgz", + "integrity": "sha512-s0hESqVwnGZCT9zbnXzrDlBOf6LTBTS5vijWOvJJOjpxNmZptCYPxEgOItuvCAi5NBf9rlSDIQyYOCDBn82HZw==", + "optional": true + }, + "@next/swc-win32-ia32-msvc": { + "version": "14.0.5-canary.20", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.0.5-canary.20.tgz", + "integrity": "sha512-0J9GWQmX4YuWHwWigY4QVNsMBBUxctAUD/2tjwo6cZYkfPa4Z56vwsN4o3pysdwMXasUvdXtrMo8ANkA9XtWkw==", + "optional": true + }, + "@next/swc-win32-x64-msvc": { + "version": "14.0.5-canary.20", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.0.5-canary.20.tgz", + "integrity": "sha512-kuFJcBNOvcY4T4xqt2UJIJl5XBD8z4XsciThth7Tq1w6Yq4g+c6LD/Fg9tcHI+XQdlcXtl1mxqYn5rkrRYa3AQ==", + "optional": true + }, + "@swc/helpers": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz", + "integrity": "sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==", + "requires": { + "tslib": "^2.4.0" + } + }, + "busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "requires": { + "streamsearch": "^1.1.0" + } + }, + "caniuse-lite": { + "version": "1.0.30001570", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001570.tgz", + "integrity": "sha512-+3e0ASu4sw1SWaoCtvPeyXp+5PsjigkSt8OXZbF9StH5pQWbxEjLAZE3n8Aup5udop1uRiKA7a4utUk/uoSpUw==" + }, + "client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" + }, + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" + }, + "graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==" + }, + "next": { + "version": "14.0.5-canary.20", + "resolved": "https://registry.npmjs.org/next/-/next-14.0.5-canary.20.tgz", + "integrity": "sha512-H3X0NQCLnqp6b9xZL0Tx3sgdWwWESlj3Md0AdCHTMdfXCNvTL2r9gjwPXtklAUizCUA22vhrcUJkqralFmmoRA==", + "requires": { + "@next/env": "14.0.5-canary.20", + "@next/swc-darwin-arm64": "14.0.5-canary.20", + "@next/swc-darwin-x64": "14.0.5-canary.20", + "@next/swc-linux-arm64-gnu": "14.0.5-canary.20", + "@next/swc-linux-arm64-musl": "14.0.5-canary.20", + "@next/swc-linux-x64-gnu": "14.0.5-canary.20", + "@next/swc-linux-x64-musl": "14.0.5-canary.20", + "@next/swc-win32-arm64-msvc": "14.0.5-canary.20", + "@next/swc-win32-ia32-msvc": "14.0.5-canary.20", + "@next/swc-win32-x64-msvc": "14.0.5-canary.20", + "@swc/helpers": "0.5.2", + "busboy": "1.6.0", + "caniuse-lite": "^1.0.30001406", + "graceful-fs": "^4.2.11", + "postcss": "8.4.31", + "styled-jsx": "5.1.1", + "watchpack": "2.4.0" + } + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "requires": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + } + }, + "react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "requires": { + "loose-envify": "^1.1.0" + } + }, + "react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "requires": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + } + }, + "scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "requires": { + "loose-envify": "^1.1.0" + } + }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" + }, + "streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==" + }, + "styled-jsx": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", + "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", + "requires": { + "client-only": "0.0.1" + } + }, + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==" + }, + "watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "requires": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + } + } + } +} diff --git a/content/blog/what-is-use-form-state-and-status/nextjs-use-form-state-and-status/package.json b/content/blog/what-is-use-form-state-and-status/nextjs-use-form-state-and-status/package.json new file mode 100644 index 00000000..66cfb28a --- /dev/null +++ b/content/blog/what-is-use-form-state-and-status/nextjs-use-form-state-and-status/package.json @@ -0,0 +1,16 @@ +{ + "name": "@unicorn-utterances/nextjs-use-form-state-and-status", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start" + }, + "dependencies": { + "next": "14.0.5-canary.20", + "react": "18.2.0", + "react-dom": "18.2.0", + "typescript": "5.2.2" + } +}