选择反应功能组件的输入元素形式

Selecting input element form of a react functional component

你能帮助一位好奇的实习开发人员吗? ^^

我在功能性 React 组件中使用表单,有 4 个“假页面”,我通过按钮控制 hide/show 其他输入元素。每次用户通过单击“下一页”按钮更改页面时,我都会调用一个函数来查看该页面上的输入是否已正确填写,如果缺少某些内容,我想显示警报并(例如)关注相应的输入.

我已经尝试使用 Jquery 但出现错误提示 $(..) 未定义。

我在一些页面上读到我可以使用 Refs 来实现这一点,但是在这些页面上说它没有指示在组件中使用太多的 refs,现在我想知道是否有另一种方法来实现我的目标.

最好的方法是什么?

我的代码:

const handlePageChange = (e, pageNumber, action) => {
        if(action === '+'){
            if(pageNumber === '1'){
                const nameArray = contactName.split('' );
                if(nameArray.length < 2 || nameArray[1] == ''){
                    alert('Please inform your full name.');
                    //$("#contactName").focus();
                }else{setPageNumber('2')}
            }
        }
    }

    return (
    <div className="row">
        <form onSubmit={handleSubmit} className="col s12">

            {pageNumber==='1' && 
            <div id='contact-section' className="row form-section">
            <label className='active form-tittle'>Informações de Contato (1/4)</label>
            <div className="input-field col s12 ">
            <input  id="contactName" type="text" className="validate" 
            value={contactName} onChange={e => setContactName(e.target.value)}
            />
            <label className='active' htmlFor="contactName">Nome</label>
            </div>

            <div className="input-field col s12">
            <input  id="contactPhones" type="text" className="validate"
            value={contactPhones} onChange={e => setContactPhones(e.target.value)}
            />
            <label className='active' htmlFor="contactPhones">Telefone de Contato</label>
            </div>

            <div className="input-field col s12">
            <input  id="contactEmail" type="email" className="validate"
            value={contactEmail} onChange={e => setContactEmail(e.target.value)}
            />
            <label className='active' htmlFor="contactEmail">E-mail</label>
            </div>
            <div className='buttons-box'>
            <a className="waves-effect waves-light yellow darken-2 btn" onClick={e=> handlePageChange(e, '1','+')}><i className="material-icons right">chevron_right</i>Next Page</a>
            </div>
            </div>}

在 React 中,鉴于 JSX 的出现,你真的不需要使用 JQuery。

如果您打算充分利用 React 的强大功能,或者您对为什么不需要 JQuery 感到困惑,我建议您阅读 this 文章。 ..

Refs provide a way to access DOM nodes or React elements created in the render method.

现在,只要看看您的代码片段,我建议您采用不同的方法。与其将所有三个“假页面”组件包装在一个表单中,不如考虑为每个“假页面”准备一个完整的表单(如果您有三个页面,则总共三个表单)。请注意,当他们点击 next 按钮时,您不必实际执行表单提交,但您可以拦截该事件,执行验证,将值累积到 React 上下文或更高级别的钩子中,然后呈现下一页。

使用 React,(就像其他事物一样)您必须学习 think 在 React 中。当你 运行 遇到这样的问题时,请确保你考虑了不同的方法,因为如果你的代码变得太像意大利面条一样,到处都是一堆引用,那么可能有一种更简单、更优雅的方法。

如果您使用React.js,我会倾向于建议formik or some framework to abstract away some of the complexity of dealing with form state and validation. It will make your life a whole lot easier. I personally use Ant Design's Steps with each Step containing a form。你总是可以 shell 输出到 scss、tailwindcss、less 或 style 属性来覆盖 Ant Design 的经典样式。

这是一个未经测试的示例,我使用 Ant Design 拼凑而成,这样您就可以从概念上理解我的出发点。

import React, { useState } from "react";
import { Form, Button, Divider, Steps, message } from "antd";
import { PageOne, PageTwo, PageThree } from "./Pages";

const { Step } = Steps;

function StepperForm() {
  const [current, setCurrent] = React.useState(0);
  const [globalValues, setGlobalValues] = useState([]);
  const [PageOneForm] = Form.useForm();
  const [PageTwoForm] = Form.useForm();
  const [PageThreeForm] = Form.useForm();
  const steps = [
    {
      title: "Page One",
      content: <PageOne formRef={PageOneForm} />,
    },
    {
      title: "Page Two",
      content: <PageTwo formRef={PageTwoForm} />,
    },
    {
      title: "Page Three",
      content: <PageThree formRef={PageThreeForm} />,
    },
  ];

  const prev = () => {
    setCurrent(current - 1);
    var it = globalValues;
    it.pop();
    setGlobalValues(it);
  };

  const next = () => {
    switch (current) {
      case 0:
        PageOneForm.validateFields()
          .then((values) => {
            setGlobalValues([values]);
            setCurrent(current + 1);
          })
          .catch((errorInfo) => {
            message.error(
              "You cannot move on until all " +
                errorInfo.errorFields.length +
                " errors are resolved."
            );
          });
        break;
      case 1:
        PageTwoForm.validateFields()
          .then((values) => {
            var it = onBoardValues;
            it.push(values);
            setGlobalValues(it);
            setCurrent(current + 1);
          })
          .catch((errorInfo) => {
            message.error(
              "You cannot move on until all " +
                errorInfo.errorFields.length +
                " errors are resolved."
            );
          });
        break;
      case 2:
        PageThreeForm.validateFields()
          .then((values) => {
            var it = onBoardValues;
            it.push(values);
            setGlobalValues(it);
            setCurrent(current + 1);
            //call api.
          })
          .catch((errorInfo) => {
            message.error(
              "You cannot move on until all " +
                errorInfo.errorFields.length +
                " errors are resolved."
            );
          });
        break;
    }
  };
  return (
    <>
      <Steps current={current}>
        {steps.map((item) => (
          <Step key={item.title} title={item.title} />
        ))}
      </Steps>

      <Divider />
      <div>{steps[current].content}</div>
      <div>
        {current > 0 && <Button onClick={() => prev()}>Previous</Button>}
        {current < steps.length - 1 && (
          <Button onClick={() => next()}>Next</Button>
        )}
        {current === steps.length - 1 && (
          <Button onClick={() => next()}>Done</Button>
        )}
      </div>
    </>
  );
}

PageOne 组件的外观

import React from "react";
import { Form, Input, Row, Col } from "antd";

export function PageOne(props) {
  const [form] = Form.useForm();
  return (
    <div>
      <Form
        size={"medium"}
        form={props.formRef}
        name="PageOne"
        label="left"
        layout="vertical"
      >
        <Row>
          <Col>
            <Form.Item
              validateTrigger="onBlur"
              name="FirstName"
              label={"First Name"}
              rules={[
                {
                  required: true,
                  message: "Please enter your first name.",
                  whitespace: true,
                },
              ]}
            >
              <Input />
            </Form.Item>
          </Col>
          <Col>
            <Form.Item
              validateTrigger="onBlur"
              name="LastName"
              label={"Last Name"}
              rules={[
                {
                  required: true,
                  message: "Please enter your last name.",
                  whitespace: true,
                },
              ]}
            >
              <Input />
            </Form.Item>
          </Col>
        </Row>
        <Row>
          <Col>
            <Form.Item
              validateTrigger="onBlur"
              name="EmailAddress"
              label="Primary E-mail"
              rules={[
                {
                  type: "email",
                  message: "Enter a valid E-mail.",
                },
                {
                  required: true,
                  message: "Please enter your E-mail.",
                },
              ]}
            >
              <Input />
            </Form.Item>
          </Col>
          <Col>
            <Form.Item
              validateTrigger="onBlur"
              name="PhoneNumber"
              label="Phone Number"
              hasFeedback
              rules={[
                {
                  required: true,
                  message: "Phone number required for MFA.",
                },
                ({ setFieldsValue }) => ({
                  validator(_, value) {
                    if (!value) {
                      return Promise.reject();
                    }
                    value = value.toString();
                    value = value.replace(/[^\d]/g, "");

                    setFieldsValue({ PhoneNumber: value });
                    if (value.length < 10) {
                      return Promise.reject(
                        "Phone number can't be less than 10 digits"
                      );
                    }
                    if (value.length > 10) {
                      return Promise.reject(
                        "Phone number can't be more than 10 digits"
                      );
                    }
                    return Promise.resolve();
                  },
                }),
              ]}
            >
              <Input />
            </Form.Item>
          </Col>
        </Row>
        <Row>
          <Col>
            <Form.Item
              validateTrigger="onBlur"
              name="Password"
              label="Password"
              rules={[
                {
                  required: true,
                  message: "Please enter your password.",
                },
              ]}
              hasFeedback
            >
              <Input.Password />
            </Form.Item>
          </Col>

          <Col>
            <Form.Item
              validateTrigger="onBlur"
              name="ConfirmPassword"
              label="Confirm Password"
              dependencies={["password"]}
              hasFeedback
              rules={[
                {
                  required: true,
                  message: "Please confirm your password.",
                },
                ({ getFieldValue }) => ({
                  validator(_, value) {
                    if (!value || getFieldValue("Password") === value) {
                      return Promise.resolve();
                    }
                    return Promise.reject(
                      "The two passwords that you entered do not match."
                    );
                  },
                }),
              ]}
            >
              <Input.Password />
            </Form.Item>
          </Col>
        </Row>
      </Form>
    </div>
  );
}

如您所见,组件框架可以为您提供很多帮助(即使有表单验证)。我个人喜欢 ANTD 包含它的方式。如果你只是在学习,为了学习而重新造轮子是有一定价值的,但过了一段时间,重要的是要学会你不需要每次都这样做。

P.S。下次,包括格式化的完整组件代码。这让我们很难阅读和理解。