next.js 设置状态会中断输入字段的更新

smdnsysy  于 2023-05-28  发布在  其他
关注(0)|答案(1)|浏览(141)

我遇到了一个问题,每当我设置const buyFormData时,数组确实得到更新,但其余代码(更新输入字段)停止工作。没有JavaScript错误。代码就挂在那里。在我的子组件上,我能够console.log并显示新数组。然而,由于代码停止更新,它只在我第一次点击“加”或“减”按钮时才起作用。
注解:“setBuyFormData(updatedValues);“允许输入自由更新,但从不更新子组件的值。
我怎么调试这个?JavaScript控制台中没有错误。
我用的是NextJs 13。
编辑:用Prettier格式化代码。我有点绝望了,我已经想了将近一个星期了。任何帮助都欢迎。

'use client';
import React from 'react';
import { MinusIcon, PlusIcon } from '@heroicons/react/20/solid';
import { useEffect, useState } from 'react';
import { FieldValues, useForm, useFormContext } from 'react-hook-form';
import TicketSummaryCard from './TicketSummaryCard';

//Typing
type EleventlyEvent = {
  event: Event;
  event_title: string;
};

function TicketSelection({ event }: EleventlyEvent) {
  const readFormData = useFormContext();

  const [buyformData, setBuyFormData] = useState([{}]);

  useEffect(() => {}, [buyformData]);

  const [formFields, setFormFields] = useState([
    {
      id: '0',
      ticketName: 'Régulier',
      description: 'Régulier',
      price: '40.00',
      limit: '5'
    },
    {
      id: '1',
      ticketName: 'Admission',
      description: 'Ceci est une description Admission',
      price: '10.00',
      limit: '10'
    },
    {
      id: '2',
      ticketName: 'VIP',
      description: 'Ceci est une description VIP',
      price: '80.00',
      limit: '1'
    },
    {
      id: '3',
      ticketName: 'ENFANT',
      description: 'Voici le billet pour enfant',
      price: '25.00',
      limit: '2'
    }
  ]);

  const handleTicketChange = (e: any, action: string) => {
    //Get the ticket Limit number from the input field data* attribute
    let buyLimit: number = e.getAttribute('data-limit');
    let fieldName: string = e.name;
    let fieldCurrentValue: number = parseInt(e.value);

    switch (action) {
      case 'plus':
        if (fieldCurrentValue < buyLimit) {
          let updatedValue: number = fieldCurrentValue + 1;
          e.value = updatedValue;
          setValue(fieldName, updatedValue);
        } else {
          //Error Message for Limit reached
          return;
        }
        break;

      case 'minus':
        if (fieldCurrentValue > 0) {
          let updatedValue: number = fieldCurrentValue - 1;
          e.value = updatedValue;
          setValue(fieldName, updatedValue);
        } else {
          //Error Message for Limit below minimum
          return;
        }
        break;
    }

    //After doing the maths update the buy list for the summary card
    updateBuyList();
  };

  const updateBuyList = () => {
    //Read all form
    let tempBuyList: FieldValues = readFormData.getValues();
    let updatedValues: {
      ticketName: string;
      ticketPrice: number;
      ticketNumber: number;
    }[] = [];

    for (var key in tempBuyList) {
      //Loop through the FieldValues in the forms
      if (tempBuyList.hasOwnProperty(key)) {
        formFields?.map((formField, index) => {
          if (key === formField.ticketName) {
            let newValues = {
              ticketName: key,
              ticketPrice: formField.price,
              ticketNumber: tempBuyList[key]
            };

            //Only add the ticket to the array if the number is defined
            if (tempBuyList[key]) {
              updatedValues.push(newValues);
            }
          }
        });
      }
    }
   //This breaks the rest of the form. if i update the value the forms break but the value gets passed only for the firstime.
    setBuyFormData(updatedValues);
  };

  const updateTicketNumber = (target) => {};

  const {
    register,
    setValue,
    formState: { errors }
  } = useFormContext();

  return (
    <>
      <main className="bg-white">
        <div className="mx-auto max-w-8xl px-4 sm:px-2">
          <div className="py-12 grid max-w-2xl grid-cols-1 grid-rows-1 items-start gap-x-8 gap-y-8 lg:mx-0 lg:max-w-none lg:grid-cols-12">
            <div className="col-span-7 lg:col-span-9 lg:col-start-1 lg:row-end-1">
              <h1 className="text-black font-semibold text-3xl">
                Selection de billets
              </h1>
              <div className="">
                {formFields.map((item, index) => (
                  <div
                    className="rounded-lg bg-white shadow-sm ring-1 ring-gray-900/5 my-10"
                    key={index}
                  >
                    <dl className="flex flex-wrap">
                      <div className="flex-auto pl-6 pt-6">
                        <span className="text-base font-semibold leading-6 text-gray-900">
                          {item.ticketName}
                        </span>
                      </div>

                      <div className="flex-none self-end px-6 pt-4">
                        <div className="mt-5 sm:ml-6 sm:mt-0 sm:flex sm:flex-shrink-0 sm:items-center">
                          <div className="flex flex-row" key={index}>
                            <button
                              type="button"
                              onClick={(e) => {
                                handleTicketChange(
                                  e.currentTarget.nextSibling,
                                  'minus'
                                );
                              }}
                              className="rounded-sm bg-[#33DEBD] p-1.5 text-black shadow-sm hover:bg-primaryhover focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-teal-600"
                            >
                              <MinusIcon
                                className="h-3 w-3 rounded"
                                aria-hidden="true"
                              />
                            </button>
                            <input
                              className="mx-auto w-12 p-0 m-0 text-center border-0 text-gray-900 bg-transparent font-semibold"
                              id={item.id}
                              data-limit={item.limit}
                              value={0}
                              {...register(item.ticketName)}
                            />
                            <button
                              type="button"
                              onClick={(e) => {
                                handleTicketChange(
                                  e.currentTarget.previousSibling,
                                  'plus'
                                );
                              }}
                              className="rounded-sm bg-[#33DEBD] p-1.5 text-black shadow-sm hover:bg-primaryhover focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-teal-600"
                            >
                              <PlusIcon
                                className="h-3 w-3 rounded"
                                aria-hidden="true"
                              />
                            </button>
                          </div>
                        </div>
                      </div>
                    </dl>
                    <div className="mt-6 border-t border-gray-900/5 px-6 py-6">
                      <dt className="text-md font-semibold leading-6 text-gray-900">
                        {item.price}
                      </dt>
                      <dl className="leading-6 font-normal text-gray-500">
                        {item.description}
                      </dl>
                    </div>
                  </div>
                ))}
              </div>
            </div>

            {/* Ticket Price summary */}

            <div className="col-span-7 lg:col-span-7 lg:row-end-1 ">
              <TicketSummaryCard event={event} buylist={buyformData} />
            </div>
          </div>
        </div>
      </main>
    </>
  );
}

export default TicketSelection;
mm9b1k5b

mm9b1k5b1#

我给你做了一个注解版本,有效地利用了React的状态。其实我没改多少,但最值得注意的是:

  • 为可能的票证及其组件外部的配置使用静态数据集(这也可以来自API)。
  • 通过复制静态状态来创建表单状态,这样就可以使用它来呈现表单。
  • 使用react-hook-form 1)设置初始值,2)进行基本验证。
  • 当用户与表单输入交互时更新状态。
  • 沿着状态传递到票证摘要。

我希望它能帮助你继续你的旅程,使这项工作。该代码在Sandbox中可用,因此您可以使用它。
祝你好运!

相关问题