首页 > 解决方案 > 在 React 中从另一个表单中提交表单

问题描述

我有一个带有表单的组件,AddExpense.tsx。表单应该有添加另一个类别的选项。这是一个单独的、解耦的表单,存储在 AddCategory.tsx 组件中。我需要这个组件以可视方式出现在 AddExpense 表单中,但不幸的是,这似乎破坏了 AddCategory 事件处理程序。如何嵌套这些表单并让它们与单独的 submitHandlers 一起使用?

添加费用.tsx:

export const AddExpense = (props: AddExpenseProps) => {
  const { user } = useAuth()
  const [addCategoryIsHidden, setAddCategoryIsHidden] = useState(true)
  const [state, setState] = useState({
    category: '',
    amount: 0, 
    notes: '', 
    date: '',
    user_id: user.info.user_id
  })
  const [validated, setValidated] = useState(false)

  const { categories } = props
  

  const handleSubmit = async(e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault()
    console.log('yo')
    const form = e.currentTarget;
    if (form.checkValidity() === true) {
      
      await fetch('/api/addExpense', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(state)
      }).then(result => {
        console.log(result)
        if (result.status === 200) {
          console.log('success!')
        } else {
          console.log('error!')
        }
      })

    } else {
      e.preventDefault();
      e.stopPropagation();
    } 
    setValidated(true);
  }

  return (
    <div className='form-wrapper'>
      <Form noValidate validated={validated} onSubmit={handleSubmit}>
        <Form.Group controlId='expenseCategory'>
          <Form.Label>Category</Form.Label>
          <Form.Control 
            required as='select'
            onChange={(e) => setState({...state, category: e.target.value })}
          >
            {categories.map((category, index) => (
              <option key={index} value={category.category_name}>{category.category_name}</option>
            ))}
          </Form.Control>
        </Form.Group>
        <a
        onClick={(e) => setAddCategoryIsHidden(false)}
        style={{cursor: 'pointer', color: 'blue', textDecoration: 'underline', textDecorationColor: 'blue'}}>
          Add a new category
        </a>
        <AddCategory hidden={addCategoryIsHidden} type='expenses'/>
        <Form.Group controlId='expenseAmount'>
          <Form.Label>Amount</Form.Label>
          <Form.Control 
            required 
            type="number"
            step=".01"
            onChange={(e) => setState({...state, amount: parseFloat(e.target.value) })}/>
          <Form.Control.Feedback type="invalid">
            Please provide a valid amount.
          </Form.Control.Feedback>
        </Form.Group> 
        <Form.Group controlId="expenseNotes">
          <Form.Label>Notes</Form.Label>
          <Form.Control 
            as="textarea" 
            rows={3} 
            placeholder="(optional)"
            onChange={(e) => setState({...state, notes: e.target.value})}/>
        </Form.Group>
        <Form.Group controlId="expenseDate">
          <Form.Label>Date</Form.Label>
          <Form.Control 
            required 
            type="date" 
            name='date_of_expense'
            onChange={(e) => setState({...state, date: e.target.value})}/>
          <Form.Control.Feedback type="invalid">
            Please select a date.
          </Form.Control.Feedback>
        </Form.Group>
        <Button variant="primary" type="submit">
          Submit
        </Button>
      </Form>
    </div>
  )
}

添加类别.tsx:

export const AddCategory = ({ type, hidden }: AddCategoryProps) => {
  const [newCategory, setNewCategory] = useState<string>()
  const { user } = useAuth()

  const handleSubmit = async(e: React.FormEvent<HTMLFormElement>) => {
    await fetch(`/api/addCategory`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        category_name: newCategory,
        user_id: user.info.user_id,
        type: type})
    })
  }

  return (
    hidden ? null : 
    <Form onSubmit={handleSubmit}>
      <Form.Group controlId='addCategory'>
        <Form.Control
          required
          type="text"
          placeholder="new category name"
          onChange={(e) => setNewCategory(e.target.value)}>
        </Form.Control>
      </Form.Group>
      <Button variant="primary" type="submit">
        Submit
      </Button>
    </Form>
  )
}

标签: reactjstypescriptforms

解决方案


HTML5 规范不允许嵌套<form>元素(参见讨论)。我不确定您使用的是什么表单库,但它可能会遵守该约定,并且当您将一个嵌套<Form>在另一个表单库中时会出现行为不端。

你需要要么

  • 通过移动到父组件<AddCategory>的底部和外部,或者像模态一样的其他地方来重组你的组件,或者<AddExpense><Form>

  • 不能<Form>在里面使用AddCategory;它看起来相当简单,因此您可以将输入连接到 auseState并使用按钮处理表单“提交” onClick,或者

  • 删除包装<Form>AddCategory仅使用父组件的处理类别创建onSubmit


推荐阅读