Am trying to save data into async storage every time a user clicks on a certain button and then have the saved data displayed on a seprate screen that i can navigate to, i found an example doing the same thing but using class components, i started learning react native using functional components only so i have no idea to transition from the class component to the functional component in this case
The code used: ( the screen doing the saving )
import React from "react";
import { StyleSheet, Text, View, Dimensions, Image } from "react-native";
import { SharedElement } from "react-native-shared-element";
import { TouchableOpacity, ScrollView } from "react-native-gesture-handler";
import MaterialCommunityIcons from "react-native-vector-icons/MaterialCommunityIcons";
import { Entypo } from "@expo/vector-icons";
import { FontAwesome } from "@expo/vector-icons";
import colors from "../config/colors";
import { SaveItem, ReadItem } from "../components/DbHelper";
const DetailScreen = (props) => {
state = { ####### getting an error on state
items: props.route.params,
saved: [],
};
onSave = (item) => {
const { saved } = this.state;
const newItems = [...saved, item];
this.setState({
saved: newItems,
});
const items = JSON.stringify(newItems);
SaveItem("saved", items)
.then((res) => {
console.warn("saved", res);
})
.catch((e) => console.warn(e));
};
goToDetails = () => {
this.setState({
saved: [],
});
this.props.navigation.navigate("SaveScreen");
};
const { width, height } = Dimensions.get("window");
const { data } = props.route.params;
return (
<View style={styles.container}>
<View>
<SharedElement id={`item.${data.id}.photo`}>
<Image
resizeMode="cover"
source={{ uri: data.img }}
style={{
width: 400,
height: 300,
borderBottomLeftRadius: 50,
//borderBottomRightRadius: 50,
}}
/>
</SharedElement>
<View
style={{
flexDirection: "row",
alignItems: "center",
position: "absolute",
bottom: 14,
left: 10,
}}
>
<SharedElement id={`item.${data.id}.profilePic`}>
<Image
resizeMode="cover"
source={{ uri: data.image }}
style={{
width: 60,
height: 60,
borderRadius: 10,
marginRight: 14,
}}
/>
</SharedElement>
<View
style={{
flex: 1,
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
}}
>
<SharedElement id={`item.${data.id}.profilePic`}>
<Image
resizeMode="cover"
source={{
uri:
"https://fertility.womenandinfants.org/app/uploads/photo-huff-post-logo.png",
}}
style={styles.blogProfilePic}
/>
</SharedElement>
<View>
<SharedElement id={`item.${data.id}.username`}>
<Text
style={{ color: "white", fontSize: 16, fontWeight: "bold" }}
>
{data.username}
</Text>
</SharedElement>
<View
style={{
flexDirection: "row",
alignItems: "center",
}}
>
<SharedElement id={`item.${data.id}.username`}>
{data.author != null ? (
<Text style={styles.blogUsername}>{data.author}</Text>
) : (
<Text style={styles.blogUsername}>Anonymous author</Text>
)}
</SharedElement>
<SharedElement id={`item.${data.id}.readtime`}>
<View style={{ bottom: 5 }}>
<Entypo
name="time-slot"
size={20}
color={colors.shade2}
style={{ top: 84, right: 210 }}
/>
<Text style={styles.readtime}>
{data.content.length / 10}min
</Text>
</View>
</SharedElement>
</View>
</View>
<View style={{ right: 20 }}>
<TouchableOpacity
onPress={() => {
this.onSave(item);
}}
>
<MaterialCommunityIcons
name="bookmark"
size={35}
color={colors.shade2}
/>
</TouchableOpacity>
<TouchableOpacity
onPress={this.goToDetails}
style={styles.button}
>
<Text style={styles.save}>View Saved</Text>
</TouchableOpacity>
</View>
</View>
</View>
<SharedElement id={`item.${data.id}.readtime`}>
<Text
style={{
color: "white",
fontSize: 14,
borderColor: "red",
borderRadius: 10,
top: 45,
left: 280,
}}
>
{data.category}
</Text>
</SharedElement>
</View>
<ScrollView style={{ paddingHorizontal: 10, paddingTop: 14 }}>
<SharedElement
id={`item.${data.id}.text`}
style={{ width: width - 30, marginBottom: 14 }}
>
<Text
style={{
fontSize: 26,
fontWeight: "bold",
lineHeight: 32,
color: "#FFFFFF",
top: 50,
}}
>
{data.title}
</Text>
</SharedElement>
<Text
style={{
fontSize: 16,
lineHeight: 28,
textAlign: "justify",
opacity: 0.5,
color: "#CDCFDE",
top: 50,
}}
>
{data.content}
</Text>
<View
style={{
marginVertical: 25,
paddingBottom: 20,
flex: 1,
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
}}
>
<TouchableOpacity
style={{ flexDirection: "row", padding: 12, alignItems: "center" }}
>
{/* <Feather name="heart" size={16} color="orange" />
<Text style={{ marginHorizontal: 10 }}>3.4k Likes</Text>*/}
</TouchableOpacity>
</View>
</ScrollView>
<View style={{ position: "absolute", top: 40, left: 10 }}>
<TouchableOpacity onPress={() => props.navigation.goBack()}>
<FontAwesome name="arrow-circle-left" size={30} color="white" />
</TouchableOpacity>
</View>
</View>
);
};
});
export default DetailScreen;
The code for storing the data:
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;
}
}
Sorry for the long code i tried to include all the parts to have a better grasp of the problem.
Your are using this
in on non-class component
instead of declaring state
you should use hooks You will need to remove all this
occurences to use hooks correctly
const DetailScreen = (props) => {
const [items, setItems] = useState(props.route.params)
const [saved, setSaved] = useState([])
onSave = (item) => {
// do this
const newItems = [...saved, item]
setSaved(newItems)
// or, better, this
setSaved(prev => [...prev, item])
// ...
I'll recommend you go through react and react-native documentation to help you understand how to work with class and functional components. This is important, as it will help get ahold of why and how things work.
Now going to your code, there are three things you need to address to get your code working;
this
property is not available in functional components. Update to your code
import React, {useState} from 'react';
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.warn("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;
React: https://reactjs.org/docs/getting-started.html React Native: https://reactnative.dev/docs/intro-react
you need to convert class based state code into hooks based approach using useState
for instance you class methods will look like this:
const [items,setItems] = useState(props.route.params);
const [saved,setSaved] = useState([]);
onSave = (item) => {
const newItems = [...saved, item];
setSaved(newItems);
const items = JSON.stringify(newItems);
SaveItem("saved", items)
.then((res) => {
console.warn("saved", res);
})
.catch((e) => console.warn(e));
};
goToDetails = () => {
setSaved([]);
props.navigation.navigate("SaveScreen");
};
for more info see this: reactdocs
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.