提交带有验证的表单

Submit form with validation

我正在编写此代码以使用 React 和 Typescript 提交表单,并且 Material-UI:

export default function OpenTicket(props: any) {
    const classes = useStyles();

    const formHandler = (e: React.FormEvent<HTMLFormElement>) => {
        e.preventDefault();
        console.log(e.target);
    };

    return (

            <Container>
                <Box m={5}>
                    <div className={classes.root}>
                      <form>

                            <TextField
                              id="outlined-full-width"
                              label="Name"                                                    
                              />
                            <Button
                               variant="contained">
                               Submit
                            </Button> 
                        </form>
                    </div>
                </Box>
            </Container>
    );
}

要求:

export interface TicketDTO {
    title?: string;
}

export async function postTicket(): Promise<AxiosResponse<TicketDTO[]>> {
  return await axios.post<TicketDTO[]>(
    `${baseUrl}/support/tickets/create`
  );
}

实现字段验证并在按下提交按钮时进行调用的正确方法是什么?

为了回答您的评论,这是您通常使用 react-hook-form 的方式:

import { useForm } from "react-hook-form";

export default function App() {
  const {
    register,
    handleSubmit,
    formState: { errors }
  } = useForm();

  // This won't be run unless all the input validations are met.
  const onSubmit = (data) => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register("firstName", { required: true, maxLength: 20 })} />
      {errors.firstName && <span>This field is required</span>}
      <input {...register("lastName", { pattern: /^[A-Za-z]+$/i })} />
      {errors.lastName && <span>This field can't be a number</span>}
      <input type="number" {...register("age", { min: 18, max: 99 })} />
      {errors.age && <span>This needs to be between 18 and 99 range</span>}
      <input type="submit" />
    </form>
  );
}

注册函数是处理验证的函数,您可以在此处阅读所有可用的验证。

https://react-hook-form.com/api/useform/register

我认为这消除了很多代码重复来处理使用反应状态的输入,而且它还使验证和与外部 UI 库的集成变得非常容易。

我有这个 sandbox 以防您想查看实际代码。

编辑:

要像您问题中的那样执行 post 请求,并使用您使用的输入,您可以执行如下操作:

import axios, { AxiosResponse } from "axios";
import { useForm } from "react-hook-form";
import "./styles.css";

interface TicketDTO {
  title: string;
}

async function postTicket(
  data: TicketDTO
): Promise<AxiosResponse<TicketDTO[]>> {
  return await axios.post<TicketDTO[]>(`baseUrl/support/tickets/create`);
}

export default function App() {
  const {
    register,
    handleSubmit,
    formState: { errors }
    // This generic will type the data response correctly.
    // So the errors object and register function will infer the types of TicketDTO.
  } = useForm<TicketDTO>();

  // This won't be run unless all the input validations are met.
  const onSubmit = async (data: TicketDTO) => {
  // This console.log won't give errors
  // console.log(data.title);
  // This console.log will give typing errors
  // console.log(data.randomValue);
    try {
      await postTicket(data);
    } catch (err) {
      console.log(err);
    }
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register("title", { required: true, maxLength: 20 })} />
      {errors.title && <span>This field is required</span>}
      <input type="submit" />
    </form>
  );
}

这里的 sandbox 和 post 不工作,因为没有有效的基础 url,但它应该做你想做的。

编辑没有反应挂钩形式。

这个例子使用了反应状态,正如我提到的,还有更多工作要做,因为您必须自己进行验证。

import axios, { AxiosResponse } from "axios";
import React from "react";

import "./styles.css";

interface TicketDTO {
  title: string;
}

async function postTicket(
  data: TicketDTO
): Promise<AxiosResponse<TicketDTO[]>> {
  return await axios.post<TicketDTO[]>(`baseUrl/support/tickets/create`);
}

export default function App() {
 // You will have to define your custom fields in separate states or one object state. this uses a separate state per input.
  const [title, setTitle] = React.useState("");
  // You will have to define the errors as well.
  const [errors, setErrors] = React.useState<TicketDTO>({
    title: ""
  });
  const onChange = (event: React.ChangeEvent<HTMLInputElement>) =>
    setTitle(event.target.value);

  const onSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
    // Prevents browser to load the document
    event.preventDefault();
    // Here you will have to do logic to handle all your inputs.
    if (title) {
      try {
        await postTicket({ title });
      } catch (err) {
        console.error(err);
      }
      setErrors({ title: "" });
    } else {
      setErrors({ title: "Title is required" });
    }
  };
  return (
    <form onSubmit={onSubmit}>
      <input name="title" value={title} onChange={onChange} />
      {errors.title && <span>This field is required</span>}
      <input type="submit" />
    </form>
  );
}

如果您不想在 React 中进行验证,也可以利用 HTML5 本机 validations。所以这只是一个这样做的问题:

import axios, { AxiosResponse } from "axios";
import React from "react";

import "./styles.css";

interface TicketDTO {
  title: string;
}

async function postTicket(
  data: TicketDTO
): Promise<AxiosResponse<TicketDTO[]>> {
  return await axios.post<TicketDTO[]>(`baseUrl/support/tickets/create`);
}

export default function App() {
  const [title, setTitle] = React.useState("");
  const onChange = (event: React.ChangeEvent<HTMLInputElement>) =>
    setTitle(event.target.value);

  const onSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
    // Prevents browser to load the document
    event.preventDefault();
      try {
        await postTicket({ title });
      } catch (err) {
        console.error(err);
      }
  };
  return (
    <form onSubmit={onSubmit}>
      {/* required prop makes usage of native html5 validation */}
      <input name="title" value={title} required onChange={onChange} />
      <input type="submit" />
    </form>
  );
}