You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React JS中使用Hooks实现模态框提交成功后追加HTML

现有代码问题点
  • 请求头配置错误:Access-Control-Allow-Origin是服务端返回的响应头,前端手动添加无效;FormData类型的请求浏览器会自动生成带分隔符的Content-Type,手动写死multipart/form-data会丢失分隔符导致上传失败。
  • 渲染逻辑不符合React设计:你尝试往数组里push原生HTML字符串的写法是原生JS的DOM操作思路,React是数据驱动视图,且你代码中append变量没有通过useState声明为响应式状态,即使push内容也不会触发页面更新。
  • 硬编码HTML存在ID重复问题:你写死了所有折叠面板、按钮的ID,多次追加内容后会出现ID冲突,导致折叠、点击等功能失效。
  • 异常处理缺失:catch块直接抛出错误没有用户提示,提交失败时用户无感知。
React Hooks 实现方案

1. 声明响应式状态

用useState管理清单项列表、表单字段、模态框显隐状态:

import { useState } from 'react';
import { toast } from 'react-toastify';

// 组件内部
// 清单项列表,初始值可替换为接口拉取的已有数据
const [checklist, setChecklist] = useState([]);
const [name, setName] = useState('');
const [listCategory, setListCategory] = useState('');
const [modalVisible, setModalVisible] = useState(false);

2. 修正提交逻辑

去掉错误的请求头,提交成功后通过更新状态触发视图渲染,优先使用接口返回的真实数据:

const handleSubmit = async (e) => {
  e.preventDefault();
  const formData = new FormData();
  formData.append('name', name);
  formData.append('list_category', listCategory);
  formData.append('created_by', '629829078779cc4a00139c9a');

  try {
    const { data } = await api.post('checklist', formData);
    if (data.status === '1') {
      // 新条目追加到列表状态,用接口返回的唯一ID避免重复
      setChecklist(prevList => [
        ...prevList,
        {
          id: data.data.id,
          title: data.data.name || name,
          tasks: data.data.tasks || [
            { id: 1, content: 'Reserve tables for the event date', done: false },
            { id: 2, content: 'Rent chairs and choose chair style', done: false },
            { id: 3, content: 'Rent microphone', done: false }
          ]
        }
      ]);
      // 重置表单、提示成功、关闭模态框
      setName('');
      setListCategory('');
      toast.success(data.message);
      setModalVisible(false);
    } else {
      toast.error(data.message.errors.name.message);
    }
  } catch (err) {
    toast.error('提交失败,请稍后重试');
    console.error(err);
  }
};

3. JSX渲染逻辑

不要拼接HTML字符串,通过遍历状态渲染列表,动态生成唯一ID避免冲突:

return (
  <div className="page-wrapper">
    {/* 页面其他内容,比如唤起模态框的按钮 */}
    <button className="btn btn-primary" onClick={() => setModalVisible(true)}>
      新建检查清单
    </button>

    {/* 清单列表容器 */}
    <div id="accordionExample">
      {checklist.map(item => {
        const headingId = `heading-${item.id}`;
        const collapseId = `collapse-${item.id}`;
        return (
          <div className="item" key={item.id}>
            <div className="item-header" id={headingId}>
              <h2 className="mb-0">
                <button
                  className="btn btn-link"
                  type="button"
                  data-toggle="collapse"
                  data-target={`#${collapseId}`}
                  aria-expanded="true"
                  aria-controls={collapseId}
                >
                  <span className="title_heading">{item.title}</span>
                  <div className="right90" id={item.id}>
                    <a href="/">Add new task</a>
                    <i className="fa fa-angle-down"></i>
                    <img src="Assets/img/close_icon.png" alt="关闭" />
                  </div>
                </button>
              </h2>
            </div>
            <div
              id={collapseId}
              className="collapse show"
              aria-labelledby={headingId}
              data-parent="#accordionExample"
            >
              <div className="t-p">
                <div className="table-responsive">
                  <table className="table custom_table">
                    <thead>
                      <tr>
                        <th>&nbsp;</th>
                        <th>Done</th>
                        <th>Task</th>
                        <th>&nbsp;</th>
                        <th>&nbsp;</th>
                      </tr>
                    </thead>
                    <tbody>
                      {item.tasks.map(task => (
                        <tr key={task.id}>
                          <td className="custom_ty6">
                            <img src="Assets/img/delete.png" alt="删除任务" />
                          </td>
                          <td className="cuts8">
                            <label className="container99">
                              <input type="checkbox" defaultChecked={task.done} />
                              <span className="checkmark"></span>
                            </label>
                          </td>
                          <td className="custom_labe8">
                            <input type="text" placeholder={task.content} />
                            <img src="Assets/img/edit.png" alt="编辑任务" />
                          </td>
                          <td>
                            <div className="cutom_plus">
                              <img src="Assets/img/plus.png" alt="分配" />
                              Assign task
                            </div>
                          </td>
                          <td>
                            <div className="cutom_plus">
                              <img src="Assets/img/plus.png" alt="设置日期" />
                              Due Date
                            </div>
                          </td>
                        </tr>
                      ))}
                    </tbody>
                  </table>
                </div>
              </div>
            </div>
          </div>
        )
      })}
    </div>

    {/* 提交模态框 */}
    {modalVisible && (
      <div className="modal">
        <form onSubmit={handleSubmit}>
          {/* 表单字段,绑定value和onChange */}
          <input
            type="text"
            value={name}
            onChange={e => setName(e.target.value)}
            placeholder="请输入清单名称"
          />
          <div className="modal-footer">
            <button type="button" onClick={() => setModalVisible(false)}>取消</button>
            <button type="submit">确认提交</button>
          </div>
        </form>
      </div>
    )}
  </div>
)
特殊场景说明

如果必须渲染外部传入的原生HTML字符串(存在XSS注入风险,非必要不使用),需要通过dangerouslySetInnerHTML属性渲染,且必须提前做恶意代码过滤:

// 不推荐使用示例
const [htmlList, setHtmlList] = useState([]);
const appendData = () => {
  setHtmlList(prev => [...prev, /* 你的HTML字符串 */])
}
// 渲染时
{htmlList.map((html, idx) => (
  <div key={idx} dangerouslySetInnerHTML={{__html: html}} />
))}

内容的提问来源于stack exchange,提问作者jandial nidhi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 19:09:21