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

为何在Deno Fresh中用对象/数组作为useState参数会触发无限循环?

无限循环的原因及解决办法

原因分析

组件每次渲染都会执行函数体内的全部代码,问题出在Preact对不同类型状态的更新判断逻辑上:

  • 字符串(基本类型):基本类型的比较是值比较。第一次渲染时state为'hi',调用setState('a')会触发重渲染;第二次渲染时state已经是'a',再次调用setState('a')时,新旧值完全相等,Preact判定状态无变化,不会触发重渲染,因此不会循环。
  • 对象(引用类型):引用类型的比较是内存地址(引用)比较。每次组件渲染都会创建一个全新的{a: 'a'}对象,即使内容相同,内存地址也不一样。调用setState(obj)时,Preact发现新对象和旧对象引用不同,就会判定状态更新,触发重渲染。重渲染后又会创建新对象、调用setState,如此反复形成无限循环。

解决办法

1. 把对象移到组件外部

让组件每次渲染都复用同一个对象引用:

import { useState } from "preact/hooks";

// 移到组件外部,只创建一次
const obj = {a: 'a'}

export default function(){
  const [state, setState] = useState('hi')
  setState(obj)
  console.log(state)
}

2. 用useMemo缓存对象

通过useMemo固定对象引用,仅在依赖变化时重新创建:

import { useState, useMemo } from "preact/hooks";

export default function(){
  const [state, setState] = useState('hi')
  // 空依赖数组,仅组件挂载时创建一次对象
  const obj = useMemo(() => ({a: 'a'}), [])
  setState(obj)
  console.log(state)
}

3. 避免在渲染顶层调用setState

这是最规范的做法:将setState放在事件处理函数或useEffect副作用中,只在需要时触发状态更新:

import { useState, useEffect } from "preact/hooks";

export default function(){
  const [state, setState] = useState('hi')
  
  // 仅组件挂载时执行一次状态更新
  useEffect(() => {
    setState({a: 'a'})
  }, [])

  console.log(state)
  return <div>{JSON.stringify(state)}</div>
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 13:33:38