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

React类组件项目localStorage单例封装前缀异步初始化问题求解

解决方案

方案1:改造LocalStorage封装,增加异步初始化兼容

直接改造单例类,支持前缀未就绪时操作入队,前缀设置完成后自动执行队列里的操作,同时设置默认兜底前缀避免报错,侵入性最低无需修改业务组件代码:

let instance;

class LocalStorage {
    constructor() {
        if(instance){
          return instance; 
        }
        instance = this;
        // 初始化默认前缀兜底
        instance.cachePrefix = 'main';
        // 初始化就绪状态
        instance.isReady = false;
        // 未就绪时的操作队列
        instance.pendingActions = [];
    }
    
    _getKey(key, usePrefix) {
        return usePrefix ? `${this.cachePrefix}:${key}` : key;
    }

    setPrefix(prefix) {
        this.cachePrefix = prefix;
        // 前缀设置完成,标记就绪,执行所有待执行操作
        this.isReady = true;
        this.pendingActions.forEach(action => action());
        this.pendingActions = [];
    }

    set(key, value, usePrefix = true) {
        if(key == null) return;
        // 未就绪则入队
        if(!this.isReady) {
            this.pendingActions.push(() => this.set(key, value, usePrefix));
            return;
        }
        localStorage.setItem(this._getKey(key, usePrefix), value);
    }

    get(key, usePrefix = true) {
        // 读操作如果未就绪可选择直接用默认前缀读取,或者也加入队列按需调整
        if(!this.isReady) {
            return localStorage.getItem(this._getKey(key, usePrefix));
        }
        return localStorage.getItem(this._getKey(key, usePrefix));
    }
}

export const LocalStorageWrapper = new LocalStorage()

方案2:顶层Provider增加加载状态,前缀初始化完成前不渲染子应用

在已有的WalletContextProvider中新增初始化状态,异步获取网络类型前渲染加载占位,从根源避免子组件提前执行:

function WalletContextProvider({ children }) {
  // 原有状态保留,新增前缀初始化状态
  const [prefixInitialized, setPrefixInitialized] = useState(false)
  // ...其他原有状态

  useEffect(() => {
    let cancel = false

    if (!ethereum) {
      LocalStorageWrapper.setPrefix(NETWORK_TYPE_DEFAULT)
      setPrefixInitialized(true)
      return
    }

    const walletWeb3 = getWeb3(ethereum)
    setWalletWeb3(walletWeb3)
    
    walletWeb3.eth.net
      .getNetworkType()
      .then(networkType => {
        if (!cancel) {
          setNetworkType(networkType)
          LocalStorageWrapper.setPrefix(networkType)
          setPrefixInitialized(true)
        }
        return null
      })
      .catch(() => {
        setNetworkType(NETWORK_TYPE_DEFAULT)
        LocalStorageWrapper.setPrefix(NETWORK_TYPE_DEFAULT)
        setPrefixInitialized(true)
      })

    return () => {
      cancel = true
      setWalletWeb3(null)
      setNetworkType(NETWORK_TYPE_DEFAULT)
      LocalStorageWrapper.setPrefix(NETWORK_TYPE_DEFAULT)
      setPrefixInitialized(false)
    }
  }, [ethereum, chainId])

  // 前缀未初始化完成时渲染加载占位,可替换为项目统一的加载组件
  if(!prefixInitialized) {
    return <div>加载中...</div>
  }

  // 原有返回逻辑保留
  return (
    <WalletContext.Provider value={wallet}>{children}</WalletContext.Provider>
  )
}

方案3:将LocalStorage实例注入Context,类组件通过Context获取

如果需要严格保证组件获取到实例时前缀已经初始化完成,可以把LocalStorage实例放到WalletContext里,类组件通过static contextType或者WalletContext.Consumer获取实例:

  1. 先修改Context的value定义:
const wallet = useMemo(
  () => ({
    // 原有所有属性保留
    localStorage: LocalStorageWrapper,
  }),
  [
    // 原有依赖项保留
  ]
)
  1. 类组件使用示例:
import { WalletContext } from '对应路径'
class DemoClassComponent extends React.Component {
  static contextType = WalletContext;
  componentDidMount() {
    // 此时获取到的localStorage已经完成前缀初始化
    const value = this.context.localStorage.get('自定义key');
  }
  render() {
    // 原有渲染逻辑
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.10 04:18:00