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

在Immer的setter内调用sort()报错:Uncaught TypeError: 0 is read-only

问题原因及解决办法

首先要明确:Array.sort()是原地排序方法——它会直接修改调用它的原数组,而非返回一个新的排序后数组。

你碰到的报错,核心是在useImmer的setState回调(也就是immer的produce函数)内部对result执行原地修改时,触发了只读限制,具体分两种场景:

  • 如果result是来自React状态的数组(比如某个useState/useImmer的状态值),React在开发模式下会自动冻结状态对象,防止直接修改原状态。这时候在produce回调里调用result.sort(),试图修改被冻结的数组,自然会抛出“0 is read-only”的错误。
  • 哪怕result是新创建的普通数组,immer在produce回调内部的执行逻辑会对数组修改操作做特殊追踪,原地修改的行为可能和immer的代理机制冲突,进而触发只读错误。

至于把sort()移到回调外面能正常运行,是因为此时数组的修改操作脱离了immer的追踪范围,不会触发内部的只读限制——但这其实是不规范的写法,如果result是状态值,直接修改原数组会导致React状态意外变更,埋下bug隐患。

正确的解决方式

不管sort()放在哪里,都不要直接修改原数组,先复制出一个新数组再排序:

function update(result) {
  setState(draft => {
    // 用扩展运算符复制原数组,再对新数组排序
    let sortedResult = [...result].sort();
    draft.arr[0] = sortedResult;
  })
}

也可以用Array.from()实现数组复制:

let sortedResult = Array.from(result).sort();

这种写法既不会修改原数组,也能完美避开immer的限制,逻辑更安全可靠。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 08:05:13