反应本机异步存储 |行太大,无法放入 CursorWindow
React Native AsyncStorage | Row too big to fit into CursorWindow
我在 ReactNative 中使用 AsyncStorage
在设备上存储一些数据(大尺寸 >2MB),然后使用以下代码读取它
try {
const value = await AsyncStorage.getItem('date_stored_copy');
} catch (e) {
console.log(e);
}
我收到以下错误:
Row too big to fit into CursorWindow requiredPos=0, totalRows=1...
有什么方法可以增加 CursorWindow 的大小,或者有其他替代 AsyncStorage 的方法吗?
我找到了另一个提到的替代方案here
只需安装react-native-fs-store
npm i react-native-fs react-native-fs-store
react-native link react-native-fs
并像这样使用它:
import Store from "react-native-fs-store";
const AsyncStorage = new Store('store1');
它与 AsyncStorage 的 API 完全相同,因此无需更改代码
** 请注意 react-native-fs-store
比 AsyncStorage
慢,因为每个操作都同步到文件。所以你可能会注意到延迟(屏幕无响应)而 reading/writing 数据
另一种解决方案是将数据分成块然后写入。
我编写了一个使用 AsyncStorage 的包装器,它正是这样做的:https://gist.github.com/bureyburey/2345dfa88a31e00a514479be37848d42
请注意,它最初是为与 apollo-cache-persist(apollo-client 的持久性库)一起使用而编写的。
由于 graphql 以非常扁平的结构存储数据,因此该解决方案开箱即用。
对于您的情况,如果您存储的对象如下所示:
{
data: { a lot of data here }
}
那就没关系了,包装器将无法工作
但是如果你的对象看起来像这样:
{
someData: { partial data },
someMoreData: { more partial data },
....
}
那么理论上应该可以。
完全披露:我还没有彻底测试它,只将它与 apollo-cache-persist 一起使用
我也运行遇到这个问题,以下是我解决这个问题的方法:
算法基本说明:
- “键”包含您的数据将被划分的部分数。 (示例:键是“MyElementToStore”,它的值为 7,表示您的数据需要拆分的部分数,以适合 AsyncStorage 的一行中的每个部分)
- 然后每个部分将作为单独的行存储在 AsyncStorage 中,方法是在键的名称后跟部分的索引。 (示例:[“MyElementToStore0”、“MyElementToStore1”、...]
- 检索数据以相反的方式进行,检索每一行并将结果聚合到 return
- 清除存储的最后说明,在删除密钥之前删除每个部分很重要(使用最后一个函数“clearStore”以确保正确释放内存)
import AsyncStorage from "@react-native-async-storage/async-storage";
const getStore = async (key) =>
{
try
{
let store = "";
let numberOfParts = await AsyncStorage.getItem(key);
if(typeof(numberOfParts) === 'undefined' || numberOfParts === null)
return null;
else
numberOfParts = parseInt(numberOfParts);
for (let i = 0; i < numberOfParts; i++) { store += await AsyncStorage.getItem(key + i); }
if(store === "")
return null;
return JSON.parse(store);
}
catch (error)
{
console.log("Could not get [" + key + "] from store.");
console.log(error);
return null;
}
};
const saveStore = async (key, data) =>
{
try
{
const store = JSON.stringify(data).match(/.{1,1000000}/g);
store.forEach((part, index) => { AsyncStorage.setItem((key + index), part); });
AsyncStorage.setItem(key, ("" + store.length));
}
catch (error)
{
console.log("Could not save store : ");
console.log(error.message);
}
};
const clearStore = async (key) =>
{
try
{
console.log("Clearing store for [" + key + "]");
let numberOfParts = await AsyncStorage.getItem(key);
if(typeof(numberOfParts) !== 'undefined' && numberOfParts !== null)
{
numberOfParts = parseInt(numberOfParts);
for (let i = 0; i < numberOfParts; i++) { AsyncStorage.removeItem(key + i); }
AsyncStorage.removeItem(key);
}
}
catch (error)
{
console.log("Could not clear store : ");
console.log(error.message);
}
};
我在 ReactNative 中使用 AsyncStorage
在设备上存储一些数据(大尺寸 >2MB),然后使用以下代码读取它
try {
const value = await AsyncStorage.getItem('date_stored_copy');
} catch (e) {
console.log(e);
}
我收到以下错误:
Row too big to fit into CursorWindow requiredPos=0, totalRows=1...
有什么方法可以增加 CursorWindow 的大小,或者有其他替代 AsyncStorage 的方法吗?
我找到了另一个提到的替代方案here
只需安装react-native-fs-store
npm i react-native-fs react-native-fs-store
react-native link react-native-fs
并像这样使用它:
import Store from "react-native-fs-store";
const AsyncStorage = new Store('store1');
它与 AsyncStorage 的 API 完全相同,因此无需更改代码
** 请注意 react-native-fs-store
比 AsyncStorage
慢,因为每个操作都同步到文件。所以你可能会注意到延迟(屏幕无响应)而 reading/writing 数据
另一种解决方案是将数据分成块然后写入。
我编写了一个使用 AsyncStorage 的包装器,它正是这样做的:https://gist.github.com/bureyburey/2345dfa88a31e00a514479be37848d42
请注意,它最初是为与 apollo-cache-persist(apollo-client 的持久性库)一起使用而编写的。 由于 graphql 以非常扁平的结构存储数据,因此该解决方案开箱即用。
对于您的情况,如果您存储的对象如下所示:
{
data: { a lot of data here }
}
那就没关系了,包装器将无法工作
但是如果你的对象看起来像这样:
{
someData: { partial data },
someMoreData: { more partial data },
....
}
那么理论上应该可以。
完全披露:我还没有彻底测试它,只将它与 apollo-cache-persist 一起使用
我也运行遇到这个问题,以下是我解决这个问题的方法:
算法基本说明:
- “键”包含您的数据将被划分的部分数。 (示例:键是“MyElementToStore”,它的值为 7,表示您的数据需要拆分的部分数,以适合 AsyncStorage 的一行中的每个部分)
- 然后每个部分将作为单独的行存储在 AsyncStorage 中,方法是在键的名称后跟部分的索引。 (示例:[“MyElementToStore0”、“MyElementToStore1”、...]
- 检索数据以相反的方式进行,检索每一行并将结果聚合到 return
- 清除存储的最后说明,在删除密钥之前删除每个部分很重要(使用最后一个函数“clearStore”以确保正确释放内存)
import AsyncStorage from "@react-native-async-storage/async-storage";
const getStore = async (key) =>
{
try
{
let store = "";
let numberOfParts = await AsyncStorage.getItem(key);
if(typeof(numberOfParts) === 'undefined' || numberOfParts === null)
return null;
else
numberOfParts = parseInt(numberOfParts);
for (let i = 0; i < numberOfParts; i++) { store += await AsyncStorage.getItem(key + i); }
if(store === "")
return null;
return JSON.parse(store);
}
catch (error)
{
console.log("Could not get [" + key + "] from store.");
console.log(error);
return null;
}
};
const saveStore = async (key, data) =>
{
try
{
const store = JSON.stringify(data).match(/.{1,1000000}/g);
store.forEach((part, index) => { AsyncStorage.setItem((key + index), part); });
AsyncStorage.setItem(key, ("" + store.length));
}
catch (error)
{
console.log("Could not save store : ");
console.log(error.message);
}
};
const clearStore = async (key) =>
{
try
{
console.log("Clearing store for [" + key + "]");
let numberOfParts = await AsyncStorage.getItem(key);
if(typeof(numberOfParts) !== 'undefined' && numberOfParts !== null)
{
numberOfParts = parseInt(numberOfParts);
for (let i = 0; i < numberOfParts; i++) { AsyncStorage.removeItem(key + i); }
AsyncStorage.removeItem(key);
}
}
catch (error)
{
console.log("Could not clear store : ");
console.log(error.message);
}
};