Next.js。使用 formik 形式的服务器操作。带参数的操作不起作用

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

Next.js 14.1.4。在一个页面上选择一项服务,然后使用某些字段为此服务创建一个表单。对于表单,我使用 useFormik 和 Yup 验证。为了处理提交表单,我需要向服务器上的 CRM 系统发出请求并在那里创建潜在客户。我为此创建了一个服务器函数(使用 use server 指令)。在客户端的handleSubmit 中,我使用用户选择的参数调用此函数。服务器函数不带参数调用,没有参数一切都会发生。但任务恰恰是提出论点。我有一个类似的案例,但是可以说表格是提前呈现的。现在逻辑如下 - 显示服务选择块 - 当您单击服务时,在客户端上呈现一个表单。在提交此表单时,我无法使用参数调用服务器函数,它是不带参数调用的。

索引页

import Manager from "@/components/manager"
import Header from "@/components/header"
import { getTypes } from "@/utils/requests"


export default async function Home() {

  const types = await getTypes()

  return (
    <>
      <Header/>
      <main>
        <Manager types={types}/>
      </main>
    </>
  )
}

Manager.jsx

'use client'
import { useContext } from 'react'
import DataContext from '@/components/context/data-context'
import ServiceChoice from '@/components/organisms/service-choice'
import Form from '@/components/form'
import InlineSVG from 'react-inlinesvg'
import createFieldObject from '@/utils/create-fields-object'
import createYupSchema from '@/utils/create-yup-schema'
import Link from 'next/link'


export default function Manager ({types}) {

  const { service, setService } = useContext(DataContext)

  if (service) {

    const validationSchema = createYupSchema(service?.inputs)
    const { fields, filesKey } = createFieldObject(service?.inputs)

    return (
      <>
      <div className="instruction-container flex flex-col">
        <div className="flex justify-end">
          <button type='button' className='flex flex-row items-center cursor-pointer inherit-a-font' onClick={() => {setService(null)}}>
            К выбору услуг
            <InlineSVG src='/icons/arrow-left.svg' width={35} height={25} strokeWidth={2}/>
          </button>
        </div>
        <p className='inherit-a-font'>Мы ценим ваше время и&nbsp;стремимся обеспечить быструю и&nbsp;эффективную обработку заявок. Пожалуйста, заполняйте все&nbsp;поля в&nbsp;форме максимально корректно и&nbsp;полно. Это позволит Вам&nbsp;избежать дополнительных уточнений и&nbsp;сократить время на&nbsp;обработку вашей заявки.</p>
        <p className='inherit-a-font'>Вы всегда можете задать вопрос по заполнению, связавшись с нами по номеру телефону: <Link href='tel:88005502707'>{"8-(800)-550-27-07"}</Link></p>
        <p style={{color: 'red'}} className='inherit-a-font'>Поля,&nbsp;помеченные&nbsp;{'"*"'},&nbsp;являются обязательными к&nbsp;заполнению</p>
      </div>
      <Form inputs={service?.inputs} validationSchema={validationSchema} fields={fields} filesKey={filesKey}/>
      </>
    )
  }

  return (<ServiceChoice types={types}/>)
}

表单.jsx

/* eslint-disable react-hooks/rules-of-hooks */
'use client'

import { useFormik } from 'formik'
import InputManager from '@/components/inputs/input-manager'
import { motion } from 'framer-motion'
import { getOriginalImageUrl } from '@/utils/get-image-url'
import Link from 'next/link'
import InlineSVG from 'react-inlinesvg'
import { useContext, useState } from 'react'
import DataContext from '@/components/context/data-context'
import CircleLoader from '@/components/atoms/circle-loader'
import { createLead } from '@/utils/bx-requests'


const submitFunction = async (values, filesKey, serviceName) => {
  // try {
    console.log(values, filesKey, serviceName)
    const status = await createLead(values)
    // console.log(status)
  // }
  // catch (error) {
  //   console.log(error)
  // }
}


export default function Form ({inputs, validationSchema, fields, filesKey}) {

  if (!Array.isArray(inputs)) return (<></>)
  
  const { service } = useContext(DataContext)

  const [isLoading, setIsLoading] = useState(false)
  const [isSuccess, setIsSuccess] = useState(false)

  const formik = useFormik({
    initialValues: fields,
    validationSchema: validationSchema,
    onSubmit: (values) => {submitFunction(values, filesKey, service.name)}
  })


  return (
    <form onSubmit={formik.handleSubmit} className='flex flex-col'>
      <div className={`inputs-container flex flex-col ${isLoading || isSuccess ? 'disabled' : ''}`}>
        {inputs.map((item) => (
          <div className="input-container flex flex-col" key={item.label}>
            <label className='flex flex-row items-center flex-wrap' style={{gap: '5px'}}>
              {item.label}{item.isRequired ? <span style={{fontSize: 'inherit', fontWeight: 'inherit', color: 'red'}}> * </span> : <></>}
              {item?.file?.data && <Link href={getOriginalImageUrl(item.file)} target='_blank' alt='Ссылка на файл' className='inherit-label-font'>{`(${item.filename || "Ссылка"})`}</Link>}
              {formik.errors[item.bitrixKey] && formik.touched[item.bitrixKey] && 
                <motion.span
                  initial={{opacity: 0}}
                  animate={{opacity: 1}}
                  className='inherit-p-font'
                  style={{ color: 'red'}}>
                    {formik.errors[item.bitrixKey].toLowerCase()}
                </motion.span>
              }
            </label>
            <InputManager input={item} formik={formik}/>
          </div>
        ))}
      </div>  
      <button className="flex flex-row items-center" style={{alignSelf: 'flex-end'}} disabled={isSuccess || isLoading} type='submit'>
        <p className='inherit-input-font'>{isSuccess ? "Успешно" : "Отправить заявку"}</p>
        {isLoading ? <CircleLoader/> : <InlineSVG src='/icons/upload.svg' width={30} height={20}/>}
      </button>
    </form>
  )

}

bx-requests.jsx

"use server"
// Lead creating
export async function createLead (values) {
  console.log('in lead creating', values)
  return true
  // requests logic

}

我尝试拉出表单,以便通过创建测试页面将其呈现在服务器上 测试页

import Form from "@/components/formTest";
import { getTypes } from "@/utils/requests";

export default async function Page () {

  const types = await getTypes()
  const service = types[2].attributes

  return (
    <Form inputs={service.inputs} service={service}/>
  )
}

测试表

/* eslint-disable react-hooks/rules-of-hooks */
'use client'

import { useFormik } from 'formik'
import InputManager from '@/components/inputs/input-manager'
import { motion } from 'framer-motion'
import { getOriginalImageUrl } from '@/utils/get-image-url'
import Link from 'next/link'
import InlineSVG from 'react-inlinesvg'
import { useContext, useState } from 'react'
import DataContext from '@/components/context/data-context'
import CircleLoader from '@/components/atoms/circle-loader'
import { createLead } from '@/utils/bx-requests'
import createFieldObject from '@/utils/create-fields-object'
import createYupSchema from '@/utils/create-yup-schema'


const submitFunction = async (values, filesKey, serviceName) => {
  // try {
    console.log(values, filesKey, serviceName)
    const status = await createLead(values)
    // console.log(status)
  // }
  // catch (error) {
  //   console.log(error)
  // }
}


export default function Form ({inputs, service}) {

  const validationSchema = createYupSchema(service?.inputs)
  const { fields, filesKey } = createFieldObject(service?.inputs)


  if (!Array.isArray(inputs)) return (<></>)

  const [isLoading, setIsLoading] = useState(false)
  const [isSuccess, setIsSuccess] = useState(false)

  const formik = useFormik({
    initialValues: fields,
    validationSchema: validationSchema,
    onSubmit: (values) => {submitFunction(values, filesKey, service.name)}
  })


  return (
    <form onSubmit={formik.handleSubmit} className='flex flex-col'>
      <div className={`inputs-container flex flex-col ${isLoading || isSuccess ? 'disabled' : ''}`}>
        {inputs.map((item) => (
          <div className="input-container flex flex-col" key={item.label}>
            <label className='flex flex-row items-center flex-wrap' style={{gap: '5px'}}>
              {item.label}{item.isRequired ? <span style={{fontSize: 'inherit', fontWeight: 'inherit', color: 'red'}}> * </span> : <></>}
              {item?.file?.data && <Link href={getOriginalImageUrl(item.file)} target='_blank' alt='Ссылка на файл' className='inherit-label-font'>{`(${item.filename || "Ссылка"})`}</Link>}
              {formik.errors[item.bitrixKey] && formik.touched[item.bitrixKey] && 
                <motion.span
                  initial={{opacity: 0}}
                  animate={{opacity: 1}}
                  className='inherit-p-font'
                  style={{ color: 'red'}}>
                    {formik.errors[item.bitrixKey].toLowerCase()}
                </motion.span>
              }
            </label>
            <InputManager input={item} formik={formik}/>
          </div>
        ))}
      </div>  
      <button className="flex flex-row items-center" style={{alignSelf: 'flex-end'}} disabled={isSuccess || isLoading} type='submit'>
        <p className='inherit-input-font'>{isSuccess ? "Успешно" : "Отправить заявку"}</p>
        {isLoading ? <CircleLoader/> : <InlineSVG src='/icons/upload.svg' width={30} height={20}/>}
      </button>
    </form>
  )

}

还是不行

reactjs next.js formik
1个回答
0
投票

错误是我将 File 对象传递给服务器函数

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