已解决 |提交后试图停留在页面上,“无法获取”(使用 Typescript 编写表单)

问题描述 投票:0回答:1

在尝试不重定向已提交表单的用户后,我在将表单发送到我的表单服务时遇到了问题。

我设置了一个 Formspark 表单以在framer.com 上使用。 Framer.com 强迫我使用我不知道的 Typescript(我现在只知道 HTML CSS 和 JS)。我从 Formspark 的文档和 sitepoint 社区收集了一些想法和随机信息。如果有人创造一些空闲时间来帮助解决我的问题,我真的(真的)很感激。

TL;DR,跳到解决方案
所有问题都与我的表单的提交操作有关。基本上,主要问题是我没有在 Formspark 期望我的表单具有的“const response = ...”内添加正确的标头(Content-type 和 Accept),这有点尴尬。第二个问题(这不是我面临的问题,但最终将要面对的问题)是我没有将 formData 用作普通对象,也没有将其字符串化。最后的问题是,如果响应正常,则不使用 const 值来重置(),如果不使用 const 来表示 currentTarget,则会抛出错误。

这是我的表格(简化):

import React, { useEffect, useRef, useState } from "react"
import styled from "styled-components"

const SalesForm = styled.form`
  /*styles*/
`
const FormInput = styled.input`
  /*styles*/
`
const Button = styled.button`
  /*styles*/
`
const SuccessMessage = styled.div`
  /*styles*/
`
const ErrorMessage = styled.div`
  /*styles*/
`

export default function Form(props) {
    const captchaRef = useRef<HTMLDivElement>(null)
    const [token, setToken] = useState<string | null>(null)
    const [message, setMessage] = useState<string | null>(null)
    const [isSuccess, setIsSuccess] = useState<boolean | null>(null)

    useEffect(() => {
        console.log("Initializing hCaptcha...")
        if (window.hcaptcha) {
            window.hcaptcha.render(captchaRef.current!, {
                sitekey: "mycaptchacode",
                callback: (token: string) => {
                    console.log("hCaptcha token generated:", token)
                    setToken(token)
                },
            })
        }
    }, [])

    const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
        event.preventDefault()
        if (!token) {
            alert("Please verify that you are human.")
            return
        }

        const formData = new FormData(event.currentTarget)
        console.log("Form Data: ", Array.from(formData.entries()))

        try {
            const response = await fetch("https://submit-form.com/formid", {
                method: "POST",
                body: formData,
            })

            if (response.ok) {
                setMessage("Form successfully submitted!")
                setIsSuccess(true)
                event.currentTarget.reset()
            } else {
                const errorText = await response.text()
                console.error("Error response: ", errorText)
                setMessage(
                    "There was a problem with your submission: " + errorText
                )
                setIsSuccess(false)
            }
        } catch (error) {
            console.error("Submission error: ", error)
            setMessage(
                "There was an error submitting the form: " + error.message
            )
            setIsSuccess(false)
        }
    }

    return (
        <SalesForm id="sales-form" onSubmit={handleSubmit}>
            <script src="https://js.hcaptcha.com/1/api.js" async defer></script>
            <FormInput type="text" id="comp-name" name="comp-name" placeholder="comp-name" required/>
            <div ref={captchaRef}></div>
            <Button type="submit">Send</Button>
            {message &&
                (isSuccess ? (
                    <SuccessMessage>{message}</SuccessMessage>
                ) : (
                    <ErrorMessage>{message}</ErrorMessage>
                ))}
        </SalesForm>
    )
}

我想提供更多信息:

  • handleSubmit 正在工作,除了第一个“if”语句强制用户验证验证码(因此,我的表单具有方法和操作属性)之外,它没有任何其他内容,它也没有“异步”。我添加了其他几行,以便在提交后留在同一页面上。我只是用了
    <input type="hidden" name="_redirect" value="redirecturl.com" />
    。一直拖着我来到这里的最主要的事情就是无法保持在同一页面上。我不希望用户被重定向。
  • 基于上述所有内容,我怀疑使用验证码不是问题。我的表单服务一直在工作,直到我尝试不重定向。
  • “无法获取”是我尝试发送表单后显示在表单下方的错误。

我非常感谢您的帮助。


它应该是这样的:

/* Other lines of code that have remained unchanged.*/

const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
        const target = event.currentTarget

        event.preventDefault()
        if (!token) {
            // You don't need to include this if you are not using captcha
            // alert("Please verify that you are human.")
            // return
        }

        const formData = new FormData(event.currentTarget)
        const formDataObject = Object.fromEntries(formData.entries())
        console.log("Form Data: ", formDataObject)

        try {
            const response = await fetch("https://submit-form.com/DhrCyMyaP", {
                method: "POST",
                headers: {
                    "Content-Type": "application/json",
                    Accept: "application/json",
                },
                body: JSON.stringify(formDataObject),
            })
            console.log({ response })
            const responseData = await response.json()
            console.log({ responseData })
            if (response.ok) {
                setMessage("Form successfully submitted!")
                setIsSuccess(true)
                target.reset()
            } else {
                const errorText = await response.text()
                console.error("Error response: ", errorText)
                setMessage(
                    "There was a problem with your submission: " + errorText
                )
                setIsSuccess(false)
            }
        } catch (error) {
            console.error("Submission error: ", error)
            setMessage(
                "There was an error submitting the form: " + error.message
            )
            setIsSuccess(false)
        }
    }
/* Other lines of code that have remained unchanged.*/

非常感谢先生。最大

html reactjs typescript ajax forms
1个回答
1
投票

据我所知,它应该可以工作,前端逻辑似乎没问题。我认为您需要检查您发布的网址。有几点需要注意

防止重定向所需要做的就是在提交事件上调用

preventDefault
。所以你有
event.preventDefault()
并且效果很好。

至于其余的,我无法复制你的错误,

"Failed to fetch"
。我在 https://replit.com/@maxmezzomo/Form-Submit 上用你的代码进行了重复。我刚刚删除了验证码的提前返回和警报,我认为这也不是问题。

但是,您发布到 https://submit-form.com/formid 会返回 404,并显示消息“此表单不再存在”。即使在浏览器中,单击链接也会得到该结果。所以这是我想说的预期行为。但它与

failed to fetch
内联。我只是认为如果你想发帖,你需要有一个 id,所以类似于
https://submit-form.com/<formid>
,其中 formid 是你想要发帖的地方。

一旦您拥有指向服务器所需网址的网址,您就应该能够发出请求。在 Formspark 上,端点似乎需要以下标头https://documentation.formspark.io/examples/ajax.html#axios-with-recaptcha-v2

headers: {
  "Content-Type": "application/json",
  Accept: "application/json",
},

一旦你添加了这些,我认为它应该可以工作,你可能希望有效负载也是json,这样你就可以做类似的事情

JSON.stringify(Object.fromEntries(Object.entries(formData)))

它应该给出带有表单数据的对象的json,你需要什么取决于api的期望,但你可以研究一下。

我用这个更新了replit,似乎有效,获得200。

现在响应的代码为200,因此表单数据已成功提交。但是代码的一部分仍然会抛出一个错误,稍后会被捕获,在处理事件后您不能使用事件 currentTarget,我不知道它到底是如何工作的,但可能是因为在您处理事件时它是异步的请求 currentTarget 的响应为 null。因此,简单的方法是在发出请求之前创建对目标的引用

  const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
    const target = event.currentTarget;

    event.preventDefault()
    if (!token) {...

然后你可以使用该变量来调用重置。

现在 UI 也应该显示表单已成功提交!

© www.soinside.com 2019 - 2024. All rights reserved.