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

React组件onChange事件陷入无限循环致页面崩溃问题求解

问题根因

无限重渲染导致页面崩溃由两处代码错误直接引发,和单选框的onChange事件绑定无关:

  • 异步数据请求直接写在组件函数顶层作用域。React组件每次重渲染都会完整执行一遍函数体内的所有逻辑,你在顶层直接调用GetChallenge()发起请求,请求返回后执行的一系列setState操作会触发组件重渲染,重渲染又会再次调用GetChallenge()、再次触发状态更新,形成「渲染→发请求→更新状态→重渲染→重复发请求」的死循环。
  • React Hook调用位置违规。useParams()是React Router提供的Hook,仅允许在组件顶层或自定义Hook顶层调用,你把它写在普通异步函数GetChallenge内部,违反Hook调用规则,会触发框架报错,导致状态逻辑异常。
修复方案

按以下规则调整代码即可解决问题:

  • 所有Hook调用统一放在组件最顶层,不要嵌套在普通函数、条件判断、循环语句中。
  • 接口请求这类会产生副作用的逻辑,必须包裹在useEffect中,根据业务需求配置正确的依赖数组,避免无意义的重复执行。
  • 补充基础的请求异常捕获,避免接口报错时页面白屏。
修复后可运行代码
import { useState, useEffect } from 'react'
import { useParams } from 'react-router-dom'

const Challenge = () => {
  // 所有Hook放在组件顶层调用
  const slug = useParams()
  const [loaded, setLoaded] = useState(false)
  const [product, setProduct] = useState([])
  const [variants, setVariants] = useState([])
  const [options, setOption] = useState()
  const [metafields, setMetafields] = useState([])

  // 数据请求放入useEffect,依赖为slug,仅首次挂载或slug变化时执行
  useEffect(() => {
    const fetchProductData = async () => {
      try {
        const res = await shopifyApolloClient.query({ query: singleProduct(slug) })
        const productData = res.data.product
        setProduct(productData)
        setVariants(productData.variants.edges)
        setOption(productData.variants.edges[0].node.title)
        setMetafields(productData.metafields.edges)
        setLoaded(true)
      } catch (err) {
        console.error('商品数据加载失败:', err)
      }
    }
    fetchProductData()
  }, [slug])

  const handleOptions = (event) => {
    setOption(event.target.value)
  }

  if (loaded) {
    return (
      <div>
        {variants.map((variant) => (
          <label
            htmlFor={variant.node.title}
            key={variant.node.id}>
            <input
              type="radio"
              name="options"
              checked={variant.node.title === options}
              value={variant.node.title}
              onChange={handleOptions}
            />
            {variant.node.title}
          </label>
        ))}
      </div>
    )
  }

  return <p>Not Loaded</p>
}
补充说明
  • 你原本写的单选框受控逻辑、onChange事件绑定本身没有问题,不需要调整。
  • 除了接口请求,定时器、全局事件订阅这类副作用逻辑,同样不能直接写在组件函数顶层,否则会随每次重渲染重复绑定/执行,大概率引发性能问题或死循环。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 02:12:41