debugging 如何使用Next.JS从父组件传递函数以处理子组件中的事件?

sy5wg1nm  于 2023-10-24  发布在  其他
关注(0)|答案(1)|浏览(149)

我正在尝试开发一个Next.js组件(FormGenerator.jsx),根据传递给该组件的信息(对象数组)自动创建表单。在FormGenerator中,它迭代数组中的每个对象,根据对象中的数据呈现子组件(TextField,TextArea等)。我的目标是简化并保持我网站上40多个表单的一致性。
我能够渲染所有必要的组件,并将必要的信息传递给所述子组件;然而,我的问题围绕着事件处理程序。在我的父组件中,(FormGenerator),我存储所有子组件的状态,包括所述子组件的值和isInvalid布尔值。为了做到这一点,我给子组件传递了一个onBlur函数和一个P2P Change函数。onBlur函数用于验证,而P2P Change函数用于更新状态。
不幸的是,当输入值或用户点击关闭元素时,onBlur和OnBlur Change函数似乎不会被触发。我将在下面提供我的代码。为了简单起见,我删除了所有不必要的Tailwind.css样式。此外,我只包含了TextField组件,因为这是我的试运行;其他表单元素将在开发过程中添加。
src/app/page.jsx:

const components [{...}...] // List of components to generate using FormGenerator

const page = () => {
  return (
    ...
    <FormGenerator 
       components={components}
    />
    ...
  )
}

export default page

src/app/components/FormGenerator.jsx:

"use client";

import React, { useState } from "react";
import TextField from "./FormGeneratorLib/TextField";

const FormGenerator = ({ title, desc, components }) => {
  const initValues = ...
  const initErrors = ...

  const initState = { values: initValues, isInvalid: initErrors };
  const [state, setState] = useState(initState);
  const { values, isInvalid } = state;

  ...
 
  const onBlur = (e) => {
    console.error("onBlur Triggered") // Just for testing purposes
  }

  // function onBlur(event) { // First attempt at this
  //   console.error("onBlur Triggered");
  //   const input = event.target;
  //
  //   // Validation
  //
  //   setState((prev) => ({
  //     ...prev,
  //     isInvalid: {
  //       ...prev.isInvalid,
  //       [input.name]: true,
  //     },
  //   }));
  // }

  // Handles Component Change Event and Updates Value
  const handleChange = ({ target }) =>
    setState((prev) => ({
      ...prev,
      values: {
        ...prev.values,
        [target.name]: target.value,
      },
    }));

  return (
     ...
        <form>
          {components.map((component, index) => {
            switch (component.component) {
              case "TextField":
                return (
                  <TextField
                    key={index}
                    fieldName={component.fieldName}
                    label={component.label}
                    errorMessage={component.errorMessage}
                    fieldType={component.fieldType}
                    placeholderText={component.placeholderText}
                    isRequired={component.isRequired}
                    onChange={handleChange}
                    onBlur={onBlur}
                    value={values[component.fieldName]}
                    isInvalid={isInvalid[component.fieldName]}
                  />
                );
              default:
                return null;
            }
          })}

          <button
            className="disabled:opacity-30"
            onClick={onSubmit}
            disabled={!values[0]} // To be updated
          >
            Submit
          </button>
        </form>
     ...
  );
};

export default FormGenerator;

src/app/components/FormGeneratorLib/TextField.jsx:

"use client"

import React, { useState } from 'react'

const TextField = ({ fieldName, label, errorMessage, fieldType, placeholderText, isRequired, value, onChange, onBlur, isInvalid }) => {
  return (
    <div>
      <label>{label}</label>
      <input 
        name={fieldName}
        type={fieldType}
        required={isRequired}
        placeholder={placeholderText}
        value={value}
        onChange={onChange}
        onBlur={onBlur}
        className={
          isInvalid
           ? 'border border-red-500'
           : '...'
        }
      />
      <p className={
        isInvalid
          ? '...'
          : 'hidden'
      }
      >{errorMessage}</p>
    </div>
  )
}

export default TextField

在过去的两天里,我一直在不知疲倦地研究,观看许多YouTube视频,并向同行寻求帮助,但无济于事。我也试着调试我的代码,但我也遇到了问题,所以来回了很多。
最后,我希望在用户输入值时更新父状态,以便onChange和onBlur事件处理程序工作。
如果你有任何关于如何解决这个问题的建议,那将是非常感谢!以及,如果你认为有一个更好的方法来实现这个想法,请让我知道。
谢谢你,谢谢

lx0bsm1f

lx0bsm1f1#

使用createContext而不是传递props,并将所有值传递给子组件或onblur和OnBlur Change,如下所示
例如:

import React, { useState, createContext } from "react";
import TextField from "./FormGeneratorLib/TextField";

  export const inputContext = createContext()

const FormGenerator = ({ title, desc, components }) => {
  .......
  const onBlur = (e) => {
    console.error("onBlur Triggered") // Just for testing purposes
  }

  // Handles Component Change Event and Updates Value
  const handleChange = ({ target }) =>
    setState((prev) => ({
      ...prev,
      values: {
        ...prev.values,
        [target.name]: target.value,
      },
    }));

  return (
     ...
        <form>
          {components.map((component, index) => {
            switch (component.component) {
              case "TextField":
                return (
                  <inputContext.Provider value={{ onBlur, handleChange }}>
                  <TextField
                    key={index}
                    fieldName={component.fieldName}
                    label={component.label}
                    errorMessage={component.errorMessage}
                    fieldType={component.fieldType}
                    placeholderText={component.placeholderText}
                    isRequired={component.isRequired}
                    value={values[component.fieldName]}
                    isInvalid={isInvalid[component.fieldName]}
                  />
                  </inputContext.Provider>
                );
              default:
                return null;
            }
          })}
     ...
  );
};
export default FormGenerator;

在文本字段组件中,

import React, { useState, useContext } from 'react'
import {inputContext } from './FormGenerator.jsx'

const TextField = ({ fieldName, label, errorMessage, fieldType, placeholderText, isRequired, value, isInvalid }) => {
const {contextInput} = useContext(inputContext);
  return (
    <div>
      <label>{label}</label>
      <input 
        name={fieldName}
        type={fieldType}
        required={isRequired}
        placeholder={placeholderText}
        value={value}
        onChange={contextInput.handleChange}
        onBlur={contextInput.onBlur}
        className={
          isInvalid
           ? 'border border-red-500'
           : '...'
        }
      />

相关问题