【问题标题】:Ionic Storage : TypeError: Cannot read property 'get' of undefined离子存储:TypeError:无法读取未定义的属性“get”
【发布时间】:2021-05-29 21:27:47
【问题描述】:

从长远来看,我正在使用 Ionic Storage 来存储数据。现在我想在进入统计页面时检索数据,所以我调用了我创建的服务并在统计页面的 ngOnInit 中编写了方法,但是如果我正确理解了这个问题,它就无法识别存储类的实例化但奇怪的是,当我在 ionViewWillEnter() 中编写方法时它确实有效。我使 ngOnInit 和 ionViewWillEnter 都异步,但我仍然收到 ngOnInit 错误。如果我没记错的话,我可以使用 ionViewWillEnter 技巧,它类似于在我的用例中调用 ngOnInit 中的方法,但我仍然很好奇它为什么会出错......

统计页面的TS:

import { StatsService } from './../service/stats.service';
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-statistics',
  templateUrl: './statistics.page.html',
  styleUrls: ['./statistics.page.scss'],
})
export class StatisticsPage implements OnInit {

  testsAmount: any = 0;

  constructor(public statsService: StatsService) {}

  addJohn(){
    this.statsService.set("1", "john");
  }

  removeAll(){
    this.statsService.clearAll();
  }

  async getJohn(){
    console.log(await this.statsService.get("1"));
  }

  

  async ngOnInit() {
      await this.statsService.set("testSetngOnInit", "blabla");
      console.log("testSet initialized from the ngOnInit");
      console.log(await this.statsService.get("testSetngOnInit"));
  }

  async ionViewWillEnter(){
    await this.statsService.set("testSetionViewWillEnter", "blabla");
      console.log("testSet initialized from the ionViewWillEnter");
    console.log(await this.statsService.get("testSetionViewWillEnter"));
  }

  

}

服务的 TS:

import { Injectable } from '@angular/core';
import { Storage } from '@ionic/storage-angular';
import * as CordovaSQLiteDriver from 'localforage-cordovasqlitedriver';

@Injectable({
  providedIn: 'root'
})
export class StatsService {
  
  // private _storage: Storage | null = null;
  private _storage: Storage;

  constructor(public storage: Storage) { 
    this.init();
  }

  async init() {
    // If using, define drivers here: await this.storage.defineDriver(/*...*/);
    await this.storage.defineDriver(CordovaSQLiteDriver);
    const storage = await this.storage.create();
    this._storage = storage;
  }

  async keyExistence(key: string){
    if(await this.get(key) == null){
      return false;
    }
    else{
      return true;
    }
  }

  // Create and expose methods that users of this service can
  // call, for example:
  async set(key: string, value: any) {
    await this._storage?.set(key, value);
  }

  async clearAll() {
    await this._storage.clear();
  }

  async get(key: string) {
    return await this._storage.get(key);
  }

}

这就是我在控制台中得到的:

还有我的 IndexDB:

提前致谢!

【问题讨论】:

  • 并非如此,Angular 不使用与 AgularJS 相同的语法。在您发送的帖子中,他们在整个实例化方面遇到了问题,而在我的情况下,当我尝试在 ngOnInit 中使用它时只有一个错误
  • 此错误不是角度错误,也不是打字稿错误,也不是 ionic 框架错误,而是 Javascript 错误。这实际上与错误相同,您正在调用值为 undefined 的变量的方法或属性。
  • 我知道问题的性质,但我无法说出原因。马特早些时候建议这可能是一个时间问题,但在那种情况下,我不知道如何告诉 ngOnInit 等待服务实例化,因为据我了解,ngOnInit 不会等待构造函数完成该过程,而是等待由于某种原因,构造函数及时让 ionViewWillEnter 能够使用它......好吧,看起来你可能比我更了解这个问题,你能告诉我我可以在哪里工作来解决我的问题吗? :)

标签: typescript ionic-framework ionic-storage


【解决方案1】:

好的,我找到了答案!这个其实很简单解决,傻到没想到。。。 因此,您不必在自己的类中实例化服务,而是必须在使用它的类中实例化它,所以在我的情况下:

我在服务构造函数中的内容:

constructor(public storage: Storage) { 
    this.init();
  }

但问题是构造函数不能使用异步语句,所以你不能告诉你的类等待它,所以你需要在使用它的类的 ngOnInit 中进行初始化:

我使用该服务的页面:

async ngOnInit() {
      await this.statsService.init();
  }

希望这会帮助一些人:)

【讨论】:

  • 嗨,我的设置与上面相同,尽管我缺少这部分“await this.storage.defineDriver(CordovaSQLiteDriver);”因为我在我的离子角度应用程序中使用电容器。我不明白为什么我的存储中的数据在页面刷新后会被删除。
  • 我认为使用 Cordova 或 Capacitor 并不重要,根据 ionic 文档,这是唯一的区别:# 如果使用 Cordova,请使用 ionic cordova plugin add cordova 安装插件-sqlite-storage # 如果使用 Capacitor,请使用 npm install cordova-sqlite-storage 安装插件 所以即使你使用的是 Capacitor,你也可以使用它。奇怪的是,我相信您现在正在浏览器中测试应用程序,并且浏览器使用 indexDB 而不是 SQLite。你确定你配置正确吗?
【解决方案2】:

错误消息表明 stats.service.ts 中的第 44 行是导致问题的行。您的组件ngOnInit 确实在访问服务实例,但服务本身失败了。我想这是因为StatsService 的构造函数正在调用this.init();,但构造函数并没有等待它(我认为它不能)。因此,当您尝试在早期(在 ngOnInit 中)访问它时,this._storage 尚未初始化。

statsService.set 似乎成功的原因是因为该方法调用了this._storage?.set(key, value) - 请注意? 这是一个空条件,这意味着如果_storage 为空,那么整个表达式的计算结果为null

我不确定,但我假设ionViewWillEnter 在组件生命周期的后期被调用,并且统计服务构造函数有足够的时间来完全初始化。另一方面,ngOnInit 在组件构造函数之后被调用。

【讨论】:

  • 是的,你是对的,去掉“?”反而给片场带来了错误。似乎存储在 ngOnInit 完成后被实例化(然后在服务甚至被实例化之前?这很奇怪)。就像你说的,我们不能在构造函数上放置异步/等待,所以我真的不知道我应该调查哪个轨道
【解决方案3】:

在您的 AppComponent 中调用 init 以创建存储实例。这应该只调用一次。

export class AppComponent implements OnInit,{

  constructor(
    private storage: StorageService
    ) {}

  async ngOnInit() {
    await this.storage.init();
}

【讨论】:

    猜你喜欢
    • 2021-08-03
    • 1970-01-01
    • 2020-07-14
    • 2017-08-30
    • 1970-01-01
    • 1970-01-01
    • 2013-01-19
    • 2018-03-15
    • 2020-12-18
    相关资源
    最近更新 更多