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

React Native自定义类无法设置属性问题求助

问题分析与解决方案

嘿,这个问题我之前也碰到过!核心原因其实很简单:数据库查询是异步操作,你调用UserInfo.username的时候,异步任务还没跑完,自然拿不到更新后的值。

为什么会出现这种情况?

db.transaction和tx.executeSql都是非阻塞的异步方法——构造函数调用getUserInfo后,代码会立刻继续执行,而数据库查询还在后台慢悠悠地跑。这时候你去访问username,它还是构造函数里初始化的空字符串;等控制台打印出row.id的时候,异步任务才完成,但这时候你早就已经读取过username了。

怎么解决?

这里给你几个实用的方案,按需选就行:

方案1:用Promise封装,等待数据加载完成

把getUserInfo改成返回Promise,这样外部可以明确等待数据就绪后再使用:

class UserInfo {
  constructor(props) {
    this.username = ""
    // 初始化时启动加载,把Promise存起来供外部等待
    this.loadPromise = this.getUserInfo()
  }

  getUserInfo = () => {
    return new Promise((resolve, reject) => {
      db.transaction((tx) => {
        tx.executeSql(
          'SELECT * FROM users', 
          [], 
          (tx, results) => {
            const row = results.rows.item(0);
            console.log("UserID: " + row.id)
            this.username = row.id
            resolve(row.id) // 通知Promise加载完成
          },
          (error) => reject(error) // 捕获查询错误
        );
      });
    })
  }
}

export default (new UserInfo())

调用的时候要等Promise完成:

import UserInfo from './UserInfo'

UserInfo.loadPromise.then(() => {
  console.log(UserInfo.username) // 这里就能拿到正确的ID了
}).catch(err => {
  console.error('加载用户信息失败:', err)
})

方案2:用回调函数处理结果

如果你的项目还没用到Promise,回调函数也是个稳妥的选择:

class UserInfo {
  constructor(props) {
    this.username = ""
  }

  getUserInfo = (callback) => {
    db.transaction((tx) => {
      tx.executeSql(
        'SELECT * FROM users', 
        [], 
        (tx, results) => {
          const row = results.rows.item(0);
          this.username = row.id
          callback(null, row.id) // 成功时返回结果
        },
        (error) => callback(error, null) // 失败时返回错误
      );
    });
  }
}

export default (new UserInfo())

调用示例:

import UserInfo from './UserInfo'

UserInfo.getUserInfo((err, userId) => {
  if (!err) {
    console.log(UserInfo.username) // 或者直接用userId参数
  } else {
    console.error('查询出错:', err)
  }
})

方案3:观察者模式(适合多页面监听数据变化)

如果多个页面需要在用户信息更新后自动刷新,观察者模式会很方便:

class UserInfo {
  constructor(props) {
    this.username = ""
    this.listeners = []
    this.getUserInfo()
  }

  getUserInfo = () => {
    db.transaction((tx) => {
      tx.executeSql('SELECT * FROM users', [], (tx, results) => {
        const row = results.rows.item(0);
        this.username = row.id
        // 通知所有监听者数据更新了
        this.listeners.forEach(listener => listener(this.username))
      });
    });
  }

  // 添加监听函数
  addListener(listener) {
    this.listeners.push(listener)
    // 如果已经有数据,立刻触发一次
    if (this.username) listener(this.username)
  }

  // 移除监听(避免内存泄漏)
  removeListener(listener) {
    this.listeners = this.listeners.filter(l => l !== listener)
  }
}

export default (new UserInfo())

页面中使用:

import UserInfo from './UserInfo'

// 定义更新逻辑
const updateUserUI = (username) => {
  console.log('当前用户ID:', username)
  // 这里可以更新页面上的用户信息展示
}

// 添加监听
UserInfo.addListener(updateUserUI)

// 页面卸载时记得移除监听
// UserInfo.removeListener(updateUserUI)

总结

本质就是要处理异步操作的时机问题——不能在异步任务完成前就去读取它要更新的变量。上面的方案分别对应了"主动等待"、"回调通知"、"自动监听"三种场景,你可以根据自己的项目需求选最顺手的。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:12:20