AsyncStorage жалуется на несовместимость массивов и объектов во время mergeItem
Я пытаюсь выяснить почему AsyncStorage
в приложении React Native отказывается делать 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. ИМО структура данных грубая, но это то, с чем я работаю. Я не решил это, и я не могу изменить это.
2 ответа
Я помню, как работал с AsyncStorage
и это принципиально отличается от localStorage
потому что он возвращает обещания.
Ваш код выглядит хорошо, что делает это очень запутанным, но я внезапно подозреваю, что проблема может быть из-за отсутствия 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))
})
Это может быть классическая "не дожидаясь разрешения обещания", прежде чем перейти к асинхронной проблеме. Не удаляйте этот вопрос, если так. Это будет полезно для других, в том числе, вероятно, для меня в будущем.
Вот что я думаю происходит:
JavaScript бросает
AsyncStorage.mergeItem()
в очередь функцийЗдесь нет
await
для этой функции, которая возвращает обещаниеИнтерпретатор не ждет его разрешения и сразу переходит к следующей строке кода
Следующая строка кода отсутствует, поэтому он возвращается из
then()
блок 0,1 мс позже (имейте в виду, что это неявно делаетreturn undefined
который внутри асинхронной функции такой же, какresolve(undefined)
с тем, что он пытается разрешить всю цепочку обратно доawait AsyncStorage.getItem(THINGS_STORAGE_KEY)
obj
получает мусор 0,1 мс после этогоAsyncStorage.mergeItem()
наблюдает ложное значение, когда он ожидалobj
, но я не знаю наверняка. Возможно, он не выполняет шаг 5 или 6, а вместо этого обнаруживает, чтоmergeItem
все еще ожидает, когда он пытается решитьgetItem
цепь, в любом случае:AsyncStorage затем выдает сбивающее с толку сообщение об ошибке
То, что я в конечном итоге использовал для правильной обработки обещаний:
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()
это выглядело идентично тому, что я сделал, кроме этого звонка. Возможно, это тоже можно было попробовать, но это сработало для меня.