保存多个项目时,AsyncStorage无法正常工作



我有一个主屏幕,在那里你可以看到以卡片形式显示的多个项目。你可以通过按下它来访问项目以查看其详细信息。在详细信息屏幕上,我添加了一个书签选项,可以使用异步存储保存项目。你也可以在另一个名为savedItems屏幕的屏幕上检查保存的项目。

问题是:

  • 当我为一个项目添加书签时,它会被正确保存,我可以转到savedItems屏幕并在那里找到它,但有时我必须重新加载应用程序才能使该项目出现在savedItemss屏幕上,这是为什么?

  • 如果我预订了多个项目,它们都会被保存(在console.log上(,但由于某种原因只有最后一个出现,我永远不会在SavedItems屏幕上显示超过一个项目

Bellow是用于预订标记的代码片段(在其详细信息屏幕上保存了一个项目(

Details.js

const DetailScreen = (props) => {
const [saved, setSaved] = useState([]);
const [items, setItems] = useState(props.route.params);
const onSave = (item) => {
const newItems = [...saved, item];
setSaved(newItems);
const items = JSON.stringify(newItems);
SaveItem("saved", items).then((res) => {
console.log("saved", res);
});
};
const goToDetails = () => {
setSaved([]);
props.navigation.navigate("SaveScreen");
};
const { width, height } = Dimensions.get("window");
const { data } = props.route.params; // this returns the data from each article
//ReadItem("saved").then((res) => console.log(res));
return (
<TouchableOpacity
...
onPress={() => {
onSave(data);
}}
>
<MaterialCommunityIcons
name="bookmark"
size={35}
color={colors.shade2}
/>
</TouchableOpacity>
)

SaveScreen.js

export default class Details extends Component {

state = {
saved: [],
};
removeItem = () => {
DeleteItem("saved")
.then((res) => {
this.setState({
saved: [],
});
console.log(res);
})
.catch((e) => console.log(e));
};
componentDidMount = () => {
ReadItem("saved")
.then((res) => {
if (res) {
const saved = JSON.parse(res);
this.setState({
saved: saved,
});
}
})
.catch((e) => console.warn(e));
};
render() {
return (
<View style={styles.container}>
<FlatList
keyExtractor={(item, index) => index.toString()}
data={this.state.saved}
renderItem={({ item }) => {
return (
<TouchableScale
activeScale={0.9}
tension={50}
friction={7}
useNativeDriver
onPress={() =>
this.props.navigation.navigate("DetailScreen", { data: item })
}
>
<Card item={item} />
</TouchableScale>
);
}}
/>
{this.state.saved.length > 0 && (
<TouchableOpacity onPress={this.removeItem} style={styles.button}>
<Text style={styles.save}>Remove Key</Text>
</TouchableOpacity>
)}
</View>
);
}
}

用于使用异步存储保存数据的代码

Dbhelper.js

import { AsyncStorage } from "react-native";
export const SaveItem = async (key, value) => {
try {
await AsyncStorage.setItem(key, value);
console.log("saved");
} catch (e) {
console.log(e);
}
};
export const ReadItem = async (key) => {
try {
var result = await AsyncStorage.getItem(key);
return result;
} catch (e) {
return e;
}
};
export function MultiRead(key, onResponse, onFailure) {
try {
AsyncStorage.multiGet(key).then((values) => {
let responseMap = new Map();
values.map((result, i, data) => {
let key = data[i][0];
let value = data[i][1];
responseMap.set(key, value);
});
onResponse(responseMap);
});
} catch (error) {
onFailure(error);
}
}
export async function DeleteItem(key) {
try {
await AsyncStorage.removeItem(key);
return true;
} catch (exception) {
return false;
}
}

如果我预订了多个项目,它们都会被保存(在console.log上(,但由于某种原因只显示最后一个项目,我永远不会在SavedItems屏幕上显示超过一个项目

我认为问题是当你保存新项目时,你会删除旧项目。当您装载DetailScreen时,您必须读取旧项目。或者,您可以读取onSave方法中的项。这更安全。这取决于您的应用程序架构

const DetailScreen = (props) => {
const [items, setItems] = useState(props.route.params);

const onSave = (item) => {
let saved = [];
ReadItem("saved")
.then((res) => {
if (res) {
saved = JSON.parse(res);
}
const newItems = [...saved, item];
const items = JSON.stringify(newItems);
SaveItem("saved", items).then((res) => {
console.log("saved", res);
});
})
.catch((e) => console.warn(e));
};

const goToDetails = () => {
setSaved([]);
props.navigation.navigate("SaveScreen");
};
const { width, height } = Dimensions.get("window");
const { data } = props.route.params; // this returns the data from each article
//ReadItem("saved").then((res) => console.log(res));
return (
<TouchableOpacity
...
onPress={() => {
onSave(data);
}}
>
<MaterialCommunityIcons
name="bookmark"
size={35}
color={colors.shade2}
/>
</TouchableOpacity>
)

当我为一个项目添加书签时,它会被正确保存,我可以转到savedItems屏幕并在那里找到它,但有时我必须重新加载应用程序才能使该项目出现在savedItemss屏幕上,这是为什么?

我只知道为什么会发生这种情况。在某些情况下,您不会卸载SaveScreen。当您返回到SaveScreen组件时,不会调用DidMount。只需尝试将console.log添加到componentDidMount中,当您再现此行为时,如果console.log丢失,则意味着您的SaveScreen没有卸载

要处理所有情况,您可以尝试这样做:

export default class Details extends Component {

state = {
saved: [],
};
removeItem = () => {
DeleteItem("saved")
.then((res) => {
this.setState({
saved: [],
});
console.log(res);
})
.catch((e) => console.log(e));
};
componentDidMount = () => {
this.readItems();
this.unsubscribe = navigation.addListener('focus', this.readItems);
};
componentWillUnmount() {
this.unsubscribe();
}
readItems = () => {
ReadItem("saved")
.then((res) => {
if (res) {
const saved = JSON.parse(res);
this.setState({
saved: saved,
});
}
})
.catch((e) => console.warn(e));
}
render() { ... }
}

最新更新