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

React发送邮件表单选择下拉选项后出现无限重渲染及API调用问题

问题原因

  • emailClick()、changeDate()两个请求函数直接放在组件顶层执行,组件每次渲染都会调用这两个函数,函数内部调用setCemail、setDate更新状态又触发重新渲染,形成无限循环。
  • useEffect用法错误:React的useEffect仅支持2个参数(回调函数+单个数组格式的依赖项),你写了[date]、[cemail]两个依赖数组,实际仅第一个[date]生效,导致初始拉取数据的逻辑会在每次date变化时重复执行,进一步加剧循环。
  • 下拉选中后的API触发逻辑没有和对应状态绑定,无法做到仅选中值变化时才调用接口。

修复方案

  1. 移除组件顶层直接调用的emailClick()、changeDate(),将两个请求分别封装到对应useEffect中,绑定clientId、clientname和hid作为依赖,仅当选中的客户端/假期变更且有有效值时才触发请求。
  2. 修正初始拉取数据的useEffect依赖项为[],保证仅在组件首次挂载时执行一次拉取假期、客户端、邮件模板的逻辑。

修改后完整代码:

import Select from "react-select";
import Axios from "axios";
import React, { useState, useEffect } from "react";
export default function Form() {
  const [hday, setHday] = useState(null);
  const [date, setDate] = useState(null);
  const [hdata, setHdata] = useState([]);
  const [hid, setHid] = useState("");
  const [client, setClient] = useState([]);
  const [clientvalue, setClientValue] = useState(null);
  const [clientId, setClientId] = useState("");
  const [cemail, setCemail] = useState([]);
  const [clientname, setClientname] = useState(null);
  const [clientEmail, setClientEmail] = useState([]);
  const [message, setMessage] = useState("");
  const [fromField, setFromField] = useState("");
  const [loading, setLoading] = useState(false);

  const handleRequest = async (e) => {
    e.preventDefault();
    if (clientvalue && hday && fromField && cemail.length && clientEmail.length && message !== "") {
      setLoading(true);
      const body = {
        clientvalue,
        hday,
        fromField,
        cemail,
        clientEmail,
        message,
      };

      await Axios.post("http://localhost:3002/mail", body, {
        headers: {
          "Content-type": "application/json",
        },
      })
        .then((res) => {
          alert("Email Sent Successfully");
          setLoading(false);
          window.location.reload();
        })
        .catch((err) => {
          console.log(err);
          setLoading(false);
        });
    } else {
      alert("Please fill all required filed");
    }
  };

  const fromFieldChange = (obj) => {
    setFromField(obj.target.value);
  };

  const handleQuillChange = (e) => {
    setMessage(e.target.value);
  };

  function handleHolidayChange(obj) {
    console.log("This is object country", obj);
    setHday(obj);
    setHid(obj._id);
    setDate(null);
  }

  const onChangeClient = (obj) => {
    console.log("client object", obj);
    setClientValue(obj);
    setClientId(obj._id);
    setClientname(obj.client_name);
  };

  // 组件挂载时一次性拉取基础数据
  useEffect(() => {
    async function getHoliday() {
      const url = `http://localhost:3002/api/holidays`;
      await Axios.get(url)
        .then((response) => {
          setHdata(response.data);
        })
        .catch((err) => {
          console.log(err);
        });
    }
    getHoliday();

    async function getClient() {
      const url = `http://localhost:3002/api/client`;
      await Axios.get(url)
        .then((response) => {
          setClient(response.data);
        })
        .catch((err) => {
          console.log(err);
        });
    }
    getClient();

    async function getClientEmail() {
      const url = `http://localhost:3002/api/emailtemplates`;
      await Axios.get(url)
        .then((response) => {
          setClientEmail(response.data.map((e) => e.subject));
        })
        .catch((err) => {
          console.log(err);
        });
    }
    getClientEmail();
  }, []);

  // 选中客户端变更时拉取对应邮箱
  useEffect(() => {
    if (!clientId || !clientname) return;
    async function emailClick() {
      const url = `http://localhost:3002/api/getClientEmail/${clientId}/${clientname}`;
      Axios.get(url)
        .then((response) => {
          const temp = response.data.map((e) => e.email);
          setCemail(temp);
        })
        .catch((error) => {
          console.log(error);
        });
    }
    emailClick();
  }, [clientId, clientname]);

  // 选中假期变更时拉取对应日期
  useEffect(() => {
    if (!hid) return;
    async function changeDate() {
      const url = `http://localhost:3002/api/holiday_date/${hid}`;
      await Axios.get(url)
        .then((response) => {
          setDate(response.data.date_of_holiday);
        })
        .catch((error) => {
          console.log(error);
        });
    }
    changeDate();
  }, [hid]);

  return (
    <form onSubmit={handleRequest} method="post">
      <div className="form">
        <div className="form__wrapper">
          <div className="form__title">
            <h4>Holiday</h4>
          </div>
          <div className="form__container">
            <div className="form__containerItems">
              <div className="form__containerItem">
                <div className="form__containerItemName">
                  <label>Client</label>
                </div>
                <div className="form__containerItemField">
                  <Select
                    onChange={onChangeClient}
                    placeholder="Select Client"
                    value={clientvalue}
                    options={client}
                    getOptionLabel={(x) => x.client_name}
                    getOptionValue={(x) => x._id}
                  />
                </div>
              </div>
              <div className="form__containerItem">
                <div className="form__containerItemName">
                  <label>Holiday</label>
                </div>
                <div className="form__containerItemField">
                  <Select
                    onChange={handleHolidayChange}
                    placeholder="Select Holiday"
                    value={hday}
                    options={hdata}
                    getOptionLabel={(x) => x.holiday_name}
                    getOptionValue={(x) => x._id}
                  />
                </div>
              </div>
              <div className="form__containerItem">
                <div className="form__containerItemName">
                  <label>Date</label>
                </div>
                <div className="form__containerItemField">
                  <input type="text" placeholder="date..." value={date || ''} readOnly />
                </div>
              </div>
            </div>
          </div>
          <div className="form__container">
            <div className="form__containerItems">
              <div className="form__containerItem">
                <div className="form__containerItemName">
                  <label>From</label>
                </div>
                <div className="form__containerItemField">
                  <input
                    type="email"
                    placeholder="Sender Email.."
                    value={fromField}
                    onChange={fromFieldChange}
                  />
                </div>
              </div>
              <div className="form__containerItem">
                <div className="form__containerItemName">
                  <label>To</label>
                </div>
                <div className="form__containerItemField">
                  <input type="text" placeholder="Client Email.." value={cemail.join(',') || ''} readOnly />
                </div>
              </div>
              <div className="form__containerItem">
                <div className="form__containerItemName">
                  <label>Subject</label>
                </div>
                <div className="form__containerItemField">
                  <input type="text" placeholder="Write your Sub..." defaultValue={clientEmail} />
                </div>
              </div>
              <div className="form__containerItem">
                <div className="form__containerItemName">
                  <label>Compose Mail</label>
                  <button
                    disabled={loading}
                    type="submit"
                    className="btn btn-info"
                  >
                    Send
                  </button>
                </div>
              </div>
              <div className="form__containerItem">
                <div className="container__composeMail">
                  <textarea
                    value={message}
                    onChange={handleQuillChange}
                    className="quill"
                    placeholder="Enter Content from here..."
                  />
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </form>
  );
}

内容的提问来源于stack exchange,提问作者Achyuta Nanta Panda

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 18:45:04