From baa478a2bf225b43c130952dfd27116e49dae074 Mon Sep 17 00:00:00 2001 From: EGOIST Date: Thu, 12 May 2022 13:47:10 +0800 Subject: [PATCH] use react-hook-form --- package.json | 2 +- pnpm-lock.yaml | 51 +++-------------- src/components/common/LoginModal.tsx | 26 ++++----- src/components/common/SubscribeModal.tsx | 57 ++++++++----------- src/components/ui/Input.tsx | 27 +++++---- .../dashboard/[subdomain]/account/profile.tsx | 37 +++++------- .../[subdomain]/settings/domains.tsx | 29 +++++----- .../[subdomain]/settings/general.tsx | 44 ++++++-------- src/pages/dashboard/new-site.tsx | 30 +++++----- 9 files changed, 122 insertions(+), 181 deletions(-) diff --git a/package.json b/package.json index 75015f5b..79a5199d 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,6 @@ "dayjs": "^1.11.1", "dotenv": "^16.0.0", "form-data": "^4.0.0", - "formik": "^2.2.9", "mailgun.js": "^5.2.2", "markdown-it": "^13.0.0", "nanoid": "^3.3.3", @@ -40,6 +39,7 @@ "react": "^18.1.0", "react-avatar-editor": "^12.0.0", "react-dom": "^18.1.0", + "react-hook-form": "^7.31.1", "react-hot-toast": "^2.2.0", "react-query": "^3.39.0", "ua-parser-js": "^1.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3d3f3503..737abb25 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -35,7 +35,6 @@ specifiers: eslint: ^8.15.0 eslint-config-next: ^12.1.6 form-data: ^4.0.0 - formik: ^2.2.9 mailgun.js: ^5.2.2 markdown-it: ^13.0.0 nanoid: ^3.3.3 @@ -46,6 +45,7 @@ specifiers: react: ^18.1.0 react-avatar-editor: ^12.0.0 react-dom: ^18.1.0 + react-hook-form: ^7.31.1 react-hot-toast: ^2.2.0 react-query: ^3.39.0 tailwindcss: ^3.0.24 @@ -77,7 +77,6 @@ dependencies: dayjs: 1.11.2 dotenv: 16.0.0 form-data: 4.0.0 - formik: 2.2.9_react@18.1.0 mailgun.js: 5.2.2 markdown-it: 13.0.1 nanoid: 3.3.4 @@ -86,6 +85,7 @@ dependencies: react: 18.1.0 react-avatar-editor: 12.0.0_ef5jwxihqo6n7gxfmzogljlgcm react-dom: 18.1.0_react@18.1.0 + react-hook-form: 7.31.1_react@18.1.0 react-hot-toast: 2.2.0_ef5jwxihqo6n7gxfmzogljlgcm react-query: 3.39.0_ef5jwxihqo6n7gxfmzogljlgcm ua-parser-js: 1.0.2 @@ -2211,11 +2211,6 @@ packages: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} dev: true - /deepmerge/2.2.1: - resolution: {integrity: sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==} - engines: {node: '>=0.10.0'} - dev: false - /define-properties/1.1.4: resolution: {integrity: sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==} engines: {node: '>= 0.4'} @@ -2726,21 +2721,6 @@ packages: mime-types: 2.1.35 dev: false - /formik/2.2.9_react@18.1.0: - resolution: {integrity: sha512-LQLcISMmf1r5at4/gyJigGn0gOwFbeEAlji+N9InZF6LIMXnFNkO42sCI8Jt84YZggpD4cPWObAZaxpEFtSzNA==} - peerDependencies: - react: '>=16.8.0' - dependencies: - deepmerge: 2.2.1 - hoist-non-react-statics: 3.3.2 - lodash: 4.17.21 - lodash-es: 4.17.21 - react: 18.1.0 - react-fast-compare: 2.0.4 - tiny-warning: 1.0.3 - tslib: 1.14.1 - dev: false - /fs.realpath/1.0.0: resolution: {integrity: sha1-FQStJSMVjKpA20onh8sBQRmU6k8=} @@ -2888,12 +2868,6 @@ packages: dependencies: function-bind: 1.1.1 - /hoist-non-react-statics/3.3.2: - resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} - dependencies: - react-is: 16.13.1 - dev: false - /ignore/5.2.0: resolution: {integrity: sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==} engines: {node: '>= 4'} @@ -3169,10 +3143,6 @@ packages: path-exists: 3.0.0 dev: true - /lodash-es/4.17.21: - resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} - dev: false - /lodash.debounce/4.0.8: resolution: {integrity: sha1-gteb/zCmfEAF/9XiUVMArZyk168=} dev: false @@ -3181,10 +3151,6 @@ packages: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} dev: true - /lodash/4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - dev: false - /loose-envify/1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -3651,8 +3617,13 @@ packages: scheduler: 0.22.0 dev: false - /react-fast-compare/2.0.4: - resolution: {integrity: sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==} + /react-hook-form/7.31.1_react@18.1.0: + resolution: {integrity: sha512-QjtjZ8r8KtEBWWpcXLyQordCraTFxILtyQpaz5KLLxN2YzcC+FZ9LLtOnNGuOnzZo9gCoB+viK3ZHV9Mb2htmQ==} + engines: {node: '>=12.22.0'} + peerDependencies: + react: ^16.8.0 || ^17 || ^18 + dependencies: + react: 18.1.0 dev: false /react-hot-toast/2.2.0_ef5jwxihqo6n7gxfmzogljlgcm: @@ -3964,10 +3935,6 @@ packages: resolution: {integrity: sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=} dev: true - /tiny-warning/1.0.3: - resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==} - dev: false - /to-fast-properties/2.0.0: resolution: {integrity: sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=} engines: {node: '>=4'} diff --git a/src/components/common/LoginModal.tsx b/src/components/common/LoginModal.tsx index 376a289e..67ecddcb 100644 --- a/src/components/common/LoginModal.tsx +++ b/src/components/common/LoginModal.tsx @@ -1,9 +1,8 @@ import { Button } from "~/components/ui/Button" import { useStore } from "~/lib/store" import { Dialog } from "@headlessui/react" -import { useEffect, useState } from "react" import { trpc } from "~/lib/trpc" -import { useFormik } from "formik" +import { useForm } from "react-hook-form" export const LoginModal: React.FC = () => { const [loginModalOpened, setLoginModalOpened] = useStore((store) => [ @@ -12,16 +11,17 @@ export const LoginModal: React.FC = () => { ]) const requestLoginLink = trpc.useMutation("auth.requestLoginLink") - const form = useFormik({ - initialValues: { + const form = useForm({ + defaultValues: { email: "", }, - async onSubmit(values) { - await requestLoginLink.mutateAsync({ - email: values.email, - url: location.href, - }) - }, + }) + + const handleSubmit = form.handleSubmit((values) => { + requestLoginLink.mutate({ + email: values.email, + url: location.href, + }) }) return ( @@ -45,7 +45,7 @@ export const LoginModal: React.FC = () => { inbox and spam folder in case you can{`'`}t find it. )} -
+
diff --git a/src/components/common/SubscribeModal.tsx b/src/components/common/SubscribeModal.tsx index cd4ef9a1..a3f359b4 100644 --- a/src/components/common/SubscribeModal.tsx +++ b/src/components/common/SubscribeModal.tsx @@ -1,11 +1,11 @@ import React, { useEffect } from "react" -import { useFormik } from "formik" import { useStore } from "~/lib/store" import { Button } from "../ui/Button" import { Modal } from "../ui/Modal" import toast from "react-hot-toast" import { trpc } from "~/lib/trpc" import { Input } from "../ui/Input" +import { useForm } from "react-hook-form" export const SubscribeModal: React.FC<{ siteId: string @@ -23,25 +23,26 @@ export const SubscribeModal: React.FC<{ const unsubscribe = trpc.useMutation("site.unsubscribe") const trpcContext = trpc.useContext() - const subscribeForm = useFormik({ - initialValues: { + const subscribeForm = useForm({ + defaultValues: { newUserEmail: "", email: subscription?.email ?? true, telegram: subscription?.telegram ?? false, }, - onSubmit(values) { - subscribe.mutate({ - siteId, - email: values.email, - telegram: values.telegram, - newUser: isLoggedIn - ? undefined - : { - email: values.newUserEmail, - url: location.href, - }, - }) - }, + }) + + const handleSubscribe = subscribeForm.handleSubmit((values) => { + subscribe.mutate({ + siteId, + email: values.email, + telegram: values.telegram, + newUser: isLoggedIn + ? undefined + : { + email: values.newUserEmail, + url: location.href, + }, + }) }) useEffect(() => { @@ -70,40 +71,28 @@ export const SubscribeModal: React.FC<{

Please check your inbox (and spam folder).

) : ( - + {!isLoggedIn && (
)}
diff --git a/src/components/ui/Input.tsx b/src/components/ui/Input.tsx index 05010e21..30721e8c 100644 --- a/src/components/ui/Input.tsx +++ b/src/components/ui/Input.tsx @@ -1,14 +1,20 @@ import clsx from "clsx" -import { DetailedHTMLProps, InputHTMLAttributes } from "react" +import { DetailedHTMLProps, forwardRef, InputHTMLAttributes } from "react" -export const Input: React.FC< - DetailedHTMLProps, HTMLInputElement> & { - label?: string - addon?: string - isBlock?: boolean - error?: string - } -> = ({ label, addon, className, isBlock, error, ...inputProps }) => { +type Props = DetailedHTMLProps< + InputHTMLAttributes, + HTMLInputElement +> & { + label?: string + addon?: string + isBlock?: boolean + error?: string +} + +export const Input = forwardRef(function Input( + { label, addon, className, isBlock, error, ...inputProps }, + ref +) { const hasAddon = !!addon return (
@@ -20,6 +26,7 @@ export const Input: React.FC<
{error}
}
) -} +}) diff --git a/src/pages/dashboard/[subdomain]/account/profile.tsx b/src/pages/dashboard/[subdomain]/account/profile.tsx index c03b6eb4..2c138cd4 100644 --- a/src/pages/dashboard/[subdomain]/account/profile.tsx +++ b/src/pages/dashboard/[subdomain]/account/profile.tsx @@ -1,5 +1,5 @@ -import { useFormik } from "formik" import { useEffect } from "react" +import { useForm } from "react-hook-form" import toast from "react-hot-toast" import { AvatarForm } from "~/components/dashboard/AvatarForm" import { DashboardLayout } from "~/components/dashboard/DashboardLayout" @@ -12,16 +12,17 @@ export default function AccountProfilePage() { const viewer = trpc.useQuery(["auth.viewer"]) const updateProfile = trpc.useMutation("user.updateProfile") - const form = useFormik({ - initialValues: { + const form = useForm({ + defaultValues: { name: "", username: "", bio: "", email: "", }, - onSubmit(values) { - updateProfile.mutate(values) - }, + }) + + const handleSubmit = form.handleSubmit((values) => { + updateProfile.mutate(values) }) useEffect(() => { @@ -33,12 +34,10 @@ export default function AccountProfilePage() { useEffect(() => { if (viewer.data) { - form.setValues({ - name: viewer.data.name, - username: viewer.data.username, - bio: viewer.data.bio || "", - email: viewer.data.email, - }) + form.setValue("name", viewer.data.name) + form.setValue("username", viewer.data.username) + form.setValue("bio", viewer.data.bio || "") + form.setValue("email", viewer.data.email || "") } }, [viewer.data, form]) @@ -51,38 +50,32 @@ export default function AccountProfilePage() { )} - +
diff --git a/src/pages/dashboard/[subdomain]/settings/domains.tsx b/src/pages/dashboard/[subdomain]/settings/domains.tsx index 48f80763..43d65303 100644 --- a/src/pages/dashboard/[subdomain]/settings/domains.tsx +++ b/src/pages/dashboard/[subdomain]/settings/domains.tsx @@ -1,6 +1,6 @@ -import { useFormik } from "formik" import { useRouter } from "next/router" import { useEffect } from "react" +import { useForm } from "react-hook-form" import toast from "react-hot-toast" import { DashboardLayout } from "~/components/dashboard/DashboardLayout" import { SettingsLayout } from "~/components/dashboard/SettingsLayout" @@ -18,16 +18,17 @@ export default function SettingsDomainsPage() { const ctx = trpc.useContext() const updateSite = trpc.useMutation("site.updateSite") - const form = useFormik({ - initialValues: { + const form = useForm({ + defaultValues: { subdomain: "", }, - onSubmit(values) { - updateSite.mutate({ - site: siteResult.data!.id, - subdomain: values.subdomain, - }) - }, + }) + + const handleSubmit = form.handleSubmit((values) => { + updateSite.mutate({ + site: siteResult.data!.id, + subdomain: values.subdomain, + }) }) useEffect(() => { @@ -45,25 +46,21 @@ export default function SettingsDomainsPage() { useEffect(() => { if (siteResult.data) { - form.setValues({ - subdomain: siteResult.data.subdomain, - }) + form.setValue("subdomain", siteResult.data.subdomain) } }, [form, siteResult.data]) return ( - +
diff --git a/src/pages/dashboard/[subdomain]/settings/general.tsx b/src/pages/dashboard/[subdomain]/settings/general.tsx index 2aa2b9aa..e3d01a43 100644 --- a/src/pages/dashboard/[subdomain]/settings/general.tsx +++ b/src/pages/dashboard/[subdomain]/settings/general.tsx @@ -7,7 +7,7 @@ import { SettingsLayout } from "~/components/dashboard/SettingsLayout" import { useRouter } from "next/router" import { DashboardLayout } from "~/components/dashboard/DashboardLayout" import { trpc } from "~/lib/trpc" -import { useFormik } from "formik" +import { useForm } from "react-hook-form" export default function SiteSettingsGeneralPage() { const router = useRouter() @@ -20,28 +20,27 @@ export default function SiteSettingsGeneralPage() { const site = siteResult.data const updateSite = trpc.useMutation("site.updateSite") - const form = useFormik({ - initialValues: { + const form = useForm({ + defaultValues: { name: "", description: "", }, - onSubmit(values) { - updateSite.mutate({ - site: subdomain, - name: values.name, - description: values.description, - }) - }, + }) + + const handleSubmit = form.handleSubmit((values) => { + updateSite.mutate({ + site: subdomain, + name: values.name, + description: values.description, + }) }) useEffect(() => { if (site) { - form.setValues({ - name: site.name, - description: site.description || "", - }) + form.setValue("name", site.name) + form.setValue("description", site.description || "") } - }, [form, site]) + }, [site, form]) useEffect(() => { if (updateSite.isSuccess && updateSite.data) { @@ -63,16 +62,9 @@ export default function SiteSettingsGeneralPage() { />
)} - +
- +