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

React API调用栈溢出问题求助:表单未提交却触发请求

问题分析与解决方案

错误原因

  1. 递归调用导致栈溢出:你自定义了名为fetch的函数,内部又调用fetch(),覆盖了全局fetch API,造成函数无限递归,最终触发Maximum call stack size exceeded错误。
  2. 表单事件绑定错误:将onSubmit={fetch()}写在submit按钮上,会在组件首次渲染时立即执行函数,而非用户点击提交时触发。且表单提交事件应绑定在<form>标签上,而非按钮。
  3. Promise链式逻辑错误:then链中第二个fetch调用未返回Promise,且res作用域混乱,无法正确获取GeoApify返回的经纬度数据。
  4. 状态管理不当:weather是普通数组,组件重渲染时会被重置,需用useState存储;setDetails的回调写法错误,无法打印更新后的状态。

修复步骤

  1. 重命名自定义函数:将自定义fetch改名为fetchWeatherData,避免覆盖全局API。
  2. 修正表单事件绑定:在<form>标签上绑定onSubmit,传入函数引用并阻止表单默认提交行为(防止页面刷新)。
  3. 正确处理Promise链:先调用GeoApify API获取经纬度,解析后取results[0].lat和results[0].lon(返回结果为数组),再调用OpenWeatherMap API,最后将结果存入状态。
  4. 用useState管理天气数据:替代普通数组存储天气信息,保证数据在组件渲染中保留。
  5. 修正setState回调:将console.log放在setDetails的第二个回调参数中,确保打印更新后的状态。

完整修复代码

import { React, useState } from 'react'

export default function Home () {
    const [coord, setCoord] = useState({lat:'', lon:''})
    const [details, setDetails] = useState({city:'', state:''})
    const [weather, setWeather] = useState(null) // 用useState存储天气数据

    // 重命名函数,避免覆盖全局fetch
    const fetchWeatherData = () => {
        // 调用GeoApify API
        fetch(`https://api.geoapify.com/v1/geocode/search?city=${details.city}&state=${details.state}&format=json&apiKey=27a84d7b0c1b4d52b41acc3e82bbe239`)
        .then(res => res.json())
        .then(geoData => {
            // 获取第一个结果的经纬度
            const { lat, lon } = geoData.results[0]
            setCoord({ lat, lon })
            // 调用OpenWeatherMap API并返回Promise
            return fetch(`https://api.openweathermap.org/data/3.0/onecall?lat=${lat}&lon=${lon}&appid=544ce8f74a895e6f7bd6425293b01b47`)
        })
        .then(res => res.json())
        .then(weatherData => {
            setWeather(weatherData) // 更新天气状态
            console.log('天气数据:', weatherData)
        })
        .catch(err => {
            console.error('请求出错:', err) // 捕获错误避免崩溃
        })
    }

    return(
        <div>
            <h4>Home</h4>
            {/* 表单绑定onSubmit事件,阻止默认行为 */}
            <form id='form' onSubmit={(e) => {
                e.preventDefault()
                fetchWeatherData()
            }}>
                <p>
                    <label htmlFor='city'>City: </label>
                    <input 
                        placeholder='City' 
                        type='text' 
                        name='city' 
                        onChange={e => setDetails({...details, city:e.target.value}, () => console.log(details))} 
                        value={details.city} 
                    />
                </p>
                <p>
                    <label htmlFor='state'>State: </label>
                    <input 
                        placeholder='State' 
                        type='text' 
                        name='state' 
                        onChange={e => setDetails({...details, state:e.target.value}, () => console.log(details))} 
                        value={details.state} 
                    />
                </p>
                {/* submit按钮仅设置type=submit即可 */}
                <p><input type='submit' value='Submit' /></p>
            </form>
            {/* 可选:渲染天气数据 */}
            {weather && (
                <div className='weather-info'>
                    <h5>当前天气</h5>
                    <p>温度: {Math.round(weather.current.temp - 273.15)}°C</p>
                    <p>天气: {weather.current.weather[0].description}</p>
                </div>
            )}
        </div>
    )
}

额外说明

  • 添加catch块捕获请求错误,避免组件崩溃。
  • 增加了天气数据展示示例,可根据需求调整。
  • 生产环境建议通过后端代理请求API,避免直接暴露API密钥。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 06:25:09