【问题标题】:How to render a component inside Formik form如何在 Formik 表单中渲染组件
【发布时间】:2021-04-15 07:11:19
【问题描述】:

我遇到了麻烦,需要资深人士的帮助。 当用户单击 Formik 表单内的链接时,我需要呈现模式组件。但是那个表单已经是一个组件,所以我试图在另一个组件内渲染一个组件,该组件位于一个更大的组件内。但不工作。 模式或仍然永远打开(从加载页面)或根本没有加载。

这是我尝试过的代码。

表格:

// Dependencies
// $FlowExpectedError[cannot-resolve-module] */
import { useRouter } from "next/router";
// $FlowExpectedError[cannot-resolve-module] */
import { AnimatePresence, motion } from "framer-motion";
// $FlowExpectedError[cannot-resolve-module] */
import { setCookie } from "nookies";

import { Modal } from "../components/Common";

// Components
// $FlowExpectedError[cannot-resolve-module] */
import { ErrorMessage, Formik, Field, Form } from "formik";
import {
  Button,
  Label,
  FormField,
  FormCheckbox,
  HeadLogo,
} from "../components/Common";
// Helpers
import { axiosRequest } from "../helpers/axiosRequest";
import React, { useState } from "react";
import literals from "../utils/literals";

const GENDERS = [
  {
    label: "Female",
    val: "female",
  },
  {
    label: "Male",
    val: "male",
  },
  {
    label: "Other",
    val: "other",
  },
];

const ModalCloseButton = ({ closeCallback }) => (
  <div>
    <button
      type="button"
      className="float-right p-5 focus:outline-none"
      onClick={closeCallback}
    >
      {/* $FlowExpectedError[cannot-resolve-name] */}
      <img
        src="/icons/close.svg"
        alt="Close icon"
        className="float-right w-4"
      />
    </button>
  </div>
);

const TermsModal = ({ closeCallback }) => (
  // $FlowExpectedError[cannot-resolve-name]
  <>
    <ModalCloseButton closeCallback={closeCallback} />
    <span className="px-5 pb-5 text-lg font-bold leading-none">
      {literals.SEND_TO_FRIEND}
    </span>
    <div className="botton justify-center">
      <Button label={literals.ACCEPT} onClick={closeCallback} style="icon" />
    </div>
  </>
);

const SignupForm = ({
  validateForm,
  submitForm,
  setCheckedGender,
  checkedGender,
  openModal,
  cancelModal,
}) => (
  <Formik
    initialValues={{
      name: "",
      surnames: "",
      email: "",
      phone: "",
      birthDate: "",
      gender: "",
      password: "",
      terms: false,
    }}
    validate={validateForm}
    onSubmit={submitForm}
  >
    {({ isSubmitting, setFieldValue, values }) => {
      function handleGenderSelection(value) {
        setCheckedGender(value);
        setFieldValue("gender", value);
      }

      return (
        <Form className="flex flex-col w-full space-y-2">
          {/* $FlowExpectedError[cannot-resolve-name] */}
          <FormField
            name="name"
            inputType="text"
            className="text-input-bis focus:outline-none"
            inputPlaceholder={literals.NAME}
          />
          <FormField
            name="surnames"
            inputType="text"
            className="text-input-bis focus:outline-none"
            inputPlaceholder={literals.SURNAME}
          />
          <FormField
            name="email"
            inputType="email"
            className="text-input-bis focus:outline-none"
            inputPlaceholder={literals.EMAIL}
          />
          <FormField
            name="password"
            inputType="password"
            className="text-input-bis focus:outline-none"
            inputPlaceholder={literals.PASSWORD}
          />
          <FormField
            name="phone"
            inputType="tel"
            className="text-input-bis focus:outline-none"
            inputPlaceholder={literals.PHONE_NUMBER}
          />
          <FormField
            name="birthDate"
            inputType="date"
            className="text-input-bis focus:outline-none"
            inputPlaceholder={literals.BIRTHDATE}
          />
          <div role="group" className="signup-radio">
            {GENDERS.map((gender) => {
              return (
                <label
                  key={gender.val}
                  className={`
                  px-4 pt-3 pb-2 mr-2 border border-white rounded-gender leading-snug transition-colors duration-200
                  ${
                    checkedGender && gender.val === checkedGender
                      ? "bg-lightBlue"
                      : "transparent"
                  }
                `}
                >
                  <Field
                    type="radio"
                    name="gender"
                    value={gender.val}
                    checked={checkedGender === gender.val}
                    onChange={() => {
                      handleGenderSelection(gender.val);
                    }}
                  />
                  <p className="text-sm text-white uppercase">{gender.label}</p>
                </label>
              );
            })}
            <ErrorMessage
              name="gender"
              component="div"
              className="error-message"
            />
          </div>
          <div className="flex flex-row items-center justify-start">
            <FormCheckbox
              label={
                <p className="ml-2 text-sm text-lightBlue">
                  {literals.ACCEPT_THE}

                  <a
                    href="#"
                    className="text-white underline"
                    onClick={cancelModal()}
                  >
                    {literals.TERMS_TITLE}
                  </a>
                </p>
              }
              name="terms"
              callback={() => setFieldValue("terms", !values.terms)}
              callbackValue={!values.terms}
              fillColor="lightBlue"
              value={values.terms}
              marginBottom="4"
            />
          </div>
          <div className="pb-4">
            <Button type="submit" label={literals.SIGNUP} />
          </div>

          {/* <div className="flex flex-col items-stretch justify-start h-vh-5 flex-1 px-5 pb-5">
                <div className="flex flex-col flex-1 mt-12">
                  <a
                    href={literals.GLOBAL_TERMS}
                    target="_blank"
                    className="text-xl font-bold leading-tight"
                  >
                    <u>Download</u> our Terms &amp; Conditions
                  </a>
                </div>

                <div className="botton justify-center">
                  <Button
                    label={literals.ACCEPT}
                    onClick={() => setShowModal(false)}
                    style="icon"
                  />
                </div>
              </div>
            </Modal>
          </AnimatePresence> */}
        </Form>
      );
    }}
  </Formik>
);

function Signup(): React$Node {
  const [checkedGender, setCheckedGender] = useState();

  const [showModal, setShowModal] = useState();

  function cancelModal() {
    console.log("fechar");
    setShowModal(false);
  }

  function openModal() {
    console.log("abrir");
    setShowModal(true);
  }

  // TODO: Review validation
  function validateForm(values) {
    const errors = {};

    if (!values.name) {
      errors.name = "Required";
    }

    if (!values.surnames) {
      errors.surnames = "Required";
    }

    if (!values.email) {
      errors.email = "Required";
    }

    if (!values.password) {
      errors.password = "Required";
    }

    if (!values.phone) {
      errors.phone = "Required";
    }

    if (!values.birthDate) {
      errors.birthDate = "Required";
    }

    if (!values.gender) {
      errors.gender = "Required";
    }
    if (!values.terms) {
      errors.terms = "Required";
    }

    return errors;
  }

  async function submitForm(body, { setErrors }) {
    const res = await axiosRequest({
      method: "POST",
      url: "/auth/register",
      data: body,
    });

    if (res?.accessCookie) {
      const accessCookie = res.accessCookie;
      const refreshCookie = res.refreshCookie;
      setCookie(null, "accessToken", accessCookie.token, accessCookie.options);
      setCookie(
        null,
        "refreshToken",
        refreshCookie.token,
        refreshCookie.options
      );

      router.reload();
    } else {
      const errorData = res?.error?.response?.data || {};
      setErrors({ [errorData.field]: errorData.error });
    }
  }

  return (
    <motion.div
      className="flex flex-col min-h-full"
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      exit={{ opacity: 0 }}
    >
      <HeadLogo />
      <div className="grid w-full min-h-screen grid-cols-4 gap-4 px-5 rounded-background bg-purple">
        <div className="col-span-3 col-start-1 text-white mt-28">
          <h1 className="w-full mb-3 font-bold leading-none text-40px">
            {literals.SIGNUP_TITLE}
          </h1>
          <p className="w-full text-base font-light">
            {literals.SIGNUP_SUBTITLE}
          </p>
        </div>
        <div className="flex-col w-full col-span-4">
          {/* $FlowExpectedError[cannot-resolve-name] */}
          <SignupForm
            validateForm={validateForm}
            submitForm={submitForm}
            setCheckedGender={setCheckedGender}
            checkedGender={checkedGender}
            openModal={openModal}
            cancelModal={cancelModal}
          />
         
              <Modal cancelCallback={cancelModal} closeCallback={cancelModal}>
                <TermsModal closeCallback={cancelModal} />
              </Modal>
            
        </div>
      </div>
    </motion.div>
  );
}

export default Signup;

这是组件模态:

// @flow
import { Button } from "./Button";
// $FlowExpectedError[cannot-resolve-module]
import { motion } from "framer-motion";
type Props = {
  children: any,
  cancelCallback?: function,
  closeCallback: function,
}

export const Modal = ({
  children,
  cancelCallback,
  closeCallback,
}: Props): React$Node => {  
  return (
    // $FlowExpectedError
    <motion.div
      className="fixed inset-0 z-50 px-5 py-16 overflow-hidden bg-darkBlue bg-opacity-90 text-darkBlue"
      onClick={cancelCallback || closeCallback}
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      exit={{ opacity: 0 }}
    >
      {/* $FlowExpectedError */}
      <motion.div
        className="flex flex-col items-stretch justify-start max-h-full overflow-y-auto bg-white rounded-card"
        onClick={e => e.stopPropagation()}
        initial={{ y: 64, opacity: 0 }}
        animate={{ y: 0, opacity: 1 }}
        exit={{ y: 0, opacity: 0 }}
        transition={{
          type: "spring",
          duration: 0.5,
          bounce: 0,
        }}
      >
        {children}
      </motion.div>
    </motion.div>
  );
  
};

【问题讨论】:

    标签: javascript reactjs next.js formik


    【解决方案1】:

    我真的不明白你要做什么。如果你想定义 const 你可以这样做。 在返回前的“组件模式:”中,您可以定义constuseState 或任何您想要的。但这些常量只能在&lt;Modal&gt; 中访问。

    当然,有些组件必须在树的顶部,例如一些初始常量和props。

    P.S 在 nextjs 中,您的内部网站路由有 &lt;Link&gt; 组件:

    <Link href={'/homepage'}>
     some stuff
    </Link>
    

    您可以分享一些行为屏幕以供将来调查。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-13
      相关资源
      最近更新 更多