AsyncStorage 在 mergeItem 期间抱怨数组和对象不兼容

AsyncStorage complains of array and object incompatibility during mergeItem

我想弄清楚为什么 React Native 应用程序中的 AsyncStorage 拒绝对我的数据执行 mergeItem。我的函数如下所示:

const arrToObj = (array) =>
  array.reduce((obj, item) => {
    obj[Object.keys(item)[0]] = Object.values(item)[0]
    return obj
  }, {})

export const addThingToThing = async (title, thing) => {
  try {
    let subThings = []
    let things = {}
    await AsyncStorage.getItem(THINGS_STORAGE_KEY)
      .then((things) => {
        let subThings = []
        Object.values(JSON.parse(decks))
          .map((thing) => {
            if (Object.keys(thing)[0] === title) {
              subThings = [...Object.values(thing)[0].subThings, subThing]
            }
          })
        return { decks, subThings }
      })
      .then(({ decks, subThings }) => {
        const obj = {
          ...arrToObj(JSON.parse(things)),
          [title]: {
            subThings
          }
        }
        console.log(JSON.stringify(obj))
        AsyncStorage.mergeItem(THINGS_STORAGE_KEY,
          JSON.stringify(obj))
      })
  } catch (error) {
    console.log(`Error adding thing to thing: ${error.message}`)
  }
}

当我执行执行此操作时,我得到:

13:35:52: {"test":{"subThings":[{"one":"a","two":"a"}]},"test2":{"title":"test2","questions":[]}}
13:35:55: [Unhandled promise rejection: Error: Value [{"test":{"title":"test","subThings":[]}},{"test2":{"title":"test2","subThings":[]}}] of type org.json.JSONArray cannot be converted to JSONObject]

这很令人困惑,因为当数据打印出来时它是一个带有 {...} 的对象,但是 AsyncStorage 显示一个带有 [...] 的数组。有什么我想念的吗?这对我来说似乎很愚蠢,我似乎无法弄清楚如何让 RN 打得很好。

PS。 IMO 的数据结构很粗糙,但这正是我正在使用的。这不是我决定的,我也无法改变。

我记得曾使用 AsyncStorage,它与 localStorage 有根本的不同,因为它 returns 承诺。

你的代码看起来很好,这让这非常混乱,但我突然怀疑问题可能是由于缺少 await 关键字造成的。

尝试:

.then(async ({ decks, subThings }) => {
  const obj = {
    ...arrToObj(JSON.parse(things)),
    [title]: {
      subThings
    }
  }
  console.log(JSON.stringify(obj))
  // We are adding await here
  await AsyncStorage.mergeItem(THINGS_STORAGE_KEY, JSON.stringify(obj))
})

这可能是一个经典的 "not waiting for the Promise to resolve" 在继续之前,异步问题。如果是这样,请不要删除此问题。将来对包括我自己在内的其他人都有帮助。

这是我认为正在发生的事情:

  1. JavaScript 将 AsyncStorage.mergeItem() 抛入函数队列

  2. 没有await这个函数returns一个Promise

  3. 解释器不等待它解析并立即移动到下一行代码

  4. 没有下一行代码,所以它在 0.1 毫秒后从 then() 块 returns(请记住,它隐含地执行 return undefined异步函数内部与 resolve(undefined) 相同,关键是它试图将整个链解析回 await AsyncStorage.getItem(THINGS_STORAGE_KEY)

  5. obj 之后 0.1 毫秒收集垃圾

  6. AsyncStorage.mergeItem() 在预期 obj 的地方观察到一个虚假值,但我实际上并不确定。它可能没有执行第 5 步或第 6 步,而是在尝试解析 getItem 链时检测到 mergeItem 仍未决,无论哪种方式:

  7. AsyncStorage 然后给出一个令人困惑的错误消息

我最终用来正确处理 promise 的是:

export const addThingToThing = async (title, thing) => {
  try {
    AsyncStorage.getItem(THINGS_STORAGE_KEY, (err, things) => {
      let subThings = []
      Object.values(JSON.parse(decks))
        .map((thing) => {
          if (Object.keys(thing)[0] === title) {
            subThings = [...Object.values(thing)[0].subThings, subThing]
          }
        })
      const obj = {
        [title]: {
          title,
          subThings
        }
      }
      console.log(JSON.stringify(obj))
      AsyncStorage.mergeItem(THINGS_STORAGE_KEY,
        JSON.stringify(obj))
    })
  } catch (error) {
    console.log(`Error adding thing to thing: ${error.message}`)
  }
}

我在网上看到其他一些使用 .done() 的类似示例,除了那个调用之外,它们看起来与我所做的完全相同。这可能也值得尝试,但这对我有用。