Nuxt项目Vuex store中初始化web3js报RangeError问题求助
问题原因与解决方案
问题根因
出现
RangeError: Maximum call stack size exceeded的核心原因是Web3实例包含大量循环引用属性,而Vuex默认会将存入state的所有数据转为响应式对象,递归监听属性变化时触发了无限递归。
额外的场景差异原因:
- 组件中直接初始化不会报错,是因为没有将web3实例存入组件的响应式data中,不会触发递归监听逻辑
- 普通Vue项目运行无异常,是因为Nuxt默认开启了SSR(服务端渲染)逻辑,服务端侧做state的脱水/序列化时会全量遍历state属性,额外增加了触发无限递归的概率;普通Vue项目仅在客户端运行,若没有开启Vuex严格模式或全量序列化state的逻辑,大概率不会触发该问题。
可用解决方案
方案1:不将完整Web3实例存入Vuex(最推荐)
仅将业务需要的独立字段(如当前账户、链ID、已初始化的合约实例等)存入Vuex state,完整Web3实例封装为单例工具调用,完全避开响应式监听逻辑:
// /utils/web3.js 封装单例工具 import Web3 from "web3"; import { CONTRACT_BLOCKCHAIN_URL } from "~/contracts/contract_info"; let web3Instance = null export const getWeb3 = async () => { if (web3Instance) return web3Instance // 仅客户端初始化 if (process.client) { web3Instance = new Web3(Web3.givenProvider || CONTRACT_BLOCKCHAIN_URL) } return web3Instance }
业务侧需要调用web3相关能力时,直接导入getWeb3方法获取实例即可。
方案2:标记Web3实例为非响应式
如果确实需要将web3实例存入Vuex,可通过Vue提供的API标记实例不需要做响应式转换,跳过递归监听逻辑:
Nuxt3(Vue3)版本
import Web3 from "web3"; import { markRaw } from 'vue' import { CONTRACT_BLOCKCHAIN_URL } from "../contracts/contract_info"; export const actions = { async initWeb3({ commit }) { // 仅在客户端执行,跳过服务端渲染逻辑 if (!process.client) return try { const web3 = new Web3(Web3.givenProvider || CONTRACT_BLOCKCHAIN_URL ); // markRaw标记实例不做响应式转换 commit("INIT_WEB3", markRaw(web3)); } catch (err) { console.error(err); } }, };
Nuxt2(Vue2)版本
将markRaw替换为Object.freeze即可:
commit("INIT_WEB3", Object.freeze(web3));
内容的提问来源于stack exchange,提问作者lacuentazz0
相关产品推荐
相关产品推荐

