function CategoryCard (props) {
const [done, setDone] = React.useState(null);
let check;
React.useEffect(() => {
async function checkData() {
check = await getData(props.path);
// prints CORRECTLY
console.log(check);
}
checkData();
//prints INCORRECTLY
console.log(check);
setDone(true);
}, []);
return (
<View>
{done ? (
<Text>{check}</Text>
):(
<View style={[styles.container, styles.horizontal]}>
<ActivityIndicator size="large" color="#99ff99" />
</View>
)}
</View>
);
}
How can I get a value from an async function into my regular function in react-native?
In the above code, the first console.log prints the expected values, but the second one gives undefined, as if the async function never had any effect on the variable check.
I need the value of check from getData(props.path) in order to display it in the <Text> component.
Any ideas?
Put it in the state.
function CategoryCard (props) {
const [check, setCheck] = React.useState(null);
React.useEffect(() => {
async function checkData() {
const data = await getData(props.path);
setCheck(data);
}
checkData();
}, []);
return (
<View>
{check ? (
<Text>{check}</Text>
):(
<View style={[styles.container, styles.horizontal]}>
<ActivityIndicator size="large" color="#99ff99" />
</View>
)}
</View>
);
}
Related
i have following code returning value from AsyncStorage
const getData = async () => {
try {
let listlayana = JSON.parse(await AsyncStorage.getItem('layanan'));
return listlayana
}catch (e){
}
}
const datas = getData()
and i trying to loop this function result with this
{
datas.map((item, i) => (
<TouchableOpacity key={i}>
<View key={i} style={styles.listitem}>
<Text style={styles.listtext} >{item.nmlayanan}</Text>
<Text style={[styles.listtext, {color: "#b4b3b3"}]}> > </Text>
</View>
</TouchableOpacity>
))
}
and i got this following error
undefined is not a function (near '...datas.map...')
You can use React.useEffect and React.useState for this target like this:
const [data, setData] = React.useState(); //add this useState for the data
const getData = async () => {
try {
let listlayana = JSON.parse(await AsyncStorage.getItem("layanan"));
return listlayana;
} catch (e) {}
};
// and add this async useeffect for fetching data from asyncstorage
React.useEffect(async () => {
const scopeData = await getData();
setData(scopeData);
}, []);
and then your render function like this:
{data.map((item, i) => (
<TouchableOpacity key={i}>
<View key={i} style={styles.listitem}>
<Text style={styles.listtext}>{item.nmlayanan}</Text>
<Text style={[styles.listtext, { color: "#b4b3b3" }]}> > </Text>
</View>
</TouchableOpacity>
))}
and your component like this:
export default function SOF() {
const [data, setData] = React.useState();
const getData = async () => {
try {
let listlayana = JSON.parse(await AsyncStorage.getItem("layanan"));
return listlayana;
} catch (e) {}
};
React.useEffect(async () => {
const scopeData = await getData();
setData(scopeData);
});
return (
<View>
{data.map((item, i) => (
<TouchableOpacity key={i}>
<View key={i} style={styles.listitem}>
<Text style={styles.listtext}>{item.nmlayanan}</Text>
<Text style={[styles.listtext, { color: "#b4b3b3" }]}> > </Text>
</View>
</TouchableOpacity>
))}
</View>
);
}
What I'm trying to do is after a field name, I want to render its type which is in another state as you can see:
my code:
const FormScreen = ({route}) => {
const [FieldForm, setFieldForm] = useState([]);
const [TypeForm, setTypeForm] = useState([]);
useEffect(() => {
if (userForm.length > 0) {
return;
} else {
setFieldForm(JSON.parse(route.params.paramKey).fields);
setTypeForm(JSON.parse(route.params.paramKey).type);
console.log(FieldForm,TypeForm); // returns me: {"message":["ab","test"],"tipo":["Date","Text"]}
}
},[userForm,TypeForm]);
return (
<SafeAreaView style={{flex: 1}}>
<View>
<Text>COLLECTION :</Text>
{FieldForm.length > 0 ? (
FieldForm.map((item) => (
<Text key={uuid.v4()}>{item}</Text>
//Here I want to to map which type is the field(to use conditionals to render) but how can I make it?
))
) : (
<Text key={uuid.v4()}> Loading ...</Text>
)}
</View>
</SafeAreaView>
);
};
How can I use a map inside of a map to do it, or creating an api call to return the type of the fields?
You can definitely nest the map functions :
const FormScreen = ({route}) => {
const [FieldForm, setFieldForm] = useState([]);
const [TypeForm, setTypeForm] = useState([]);
useEffect(() => {
if (userForm.length > 0) {
return;
} else {
setFieldForm(JSON.parse(route.params.paramKey).fields);
setTypeForm(JSON.parse(route.params.paramKey).type);
console.log(FieldForm,TypeForm); // returns me: {"message":["ab","test"],"tipo":["Date","Text"]}
}
},[userForm,TypeForm]);
return (
<SafeAreaView style={{flex: 1}}>
<View>
<Text>COLLECTION :</Text>
{FieldForm.length > 0 ? (
FieldForm.map((item) => (
<>
<Text key={uuid.v4()}>{item}</Text>
<> {TypeForm.length && TypeForm.map((type) => ( // Return node )) || null};
</>
</>
))
) : (
<Text key={uuid.v4()}> Loading ...</Text>
)}
</View>
</SafeAreaView>
);
};
I'm trying to render data from a firebase get function but it isn't displaying anything. The images console.log displays 2 values but it doesn't get rendered on the page. Does anyone have suggestions why that is.
function cards(){
store.collection('users').get().then(snapshot => {
images = snapshot.docs.map(doc => doc.data().image)
console.log(images)
return images.map((doc) => {
return (
<Card style={[styles.card, styles.card1]}>
<Text style={styles.label}>A</Text>
</Card>
)
})
})
}
return (
<View>
<View style={styles.viewport}>
<CardStack style={styles.content}>
{cards()}
</CardStack>
</View>
</View>
)
}
You are trying to call a asynchrounous function and get a return from it by using a then. You will always get an undefined from it because the then finished when your function already returned undefined or in this case nothing.
Try it with using a state and handling the async call correctly like here:
import React, { useState, useEffect } from "react";
const YourComponent = () => {
const [list, setLits] = useState([]);
useEffect(() => {
const snapshot = await store.collection("users").get();
const images = [];
snapshot.docs.forEach((s) => {
images.push(doc.data().image);
});
setLits(images);
}, []);
return (
<View>
<View style={styles.viewport}>
<CardStack style={styles.content}>
{list.map((i) => {
return (
<Card style={[styles.card, styles.card1]}>
<Text style={styles.label}>A</Text>
</Card>
);
})}
</CardStack>
</View>
</View>
);
};
I'm really new to JS and React. I get this error:
Invalid Hook Call
when I try to make a component appear and disappear when another component is clicked. This is my code:
const RenderList = ({data}) => {
return data.map((option, index) => {
return <Item title={option}/>
});
};
const Header = ({ title, style, press }) => (
<TouchableHighlight onPress={press}>
<Text style={style} >{title}</Text>
</TouchableHighlight>
)
const RenderItem = ( {item} ) => {
console.log(styles)
let dataToShow;
const [listState, setListState] = useState(true);
if (listState){
dataToShow = <RenderList data={item.data}/>
} else {
dataToShow = <Text/>
}
return (
<View style={styles.section}>
<Header title={item.title} style={styles.header} press={setListState(!listState)}/>
{dataToShow}
</View>
)}
EDIT
RenderItem is used in a flat list element as a function. (From what I understand)
const SettingsSection = (props) => {
const db = props.data;
return(
<View>
<FlatList
style={styles.sectionList}
data={db}
renderItem={RenderItem}
keyExtractor={item=>item.title}
ItemSeparatorComponent={FlatListItemSeparator}
/>
</View>
);
}
renderItem, as the name suggests, is a render prop, and as such is called directly (like so: renderItem({item})), not instantiated as a component (like so: <RenderItem item={item}/>).
This translates to React not creating the appropriate rendering "context" for hooks to work. You can make sure your RenderItem function is instantiated as a component by using it like this on the render prop:
<FlatList
style={styles.sectionList}
data={db}
renderItem={item => <RenderItem {...item}/>} // see here!
keyExtractor={item=>item.title}
ItemSeparatorComponent={FlatListItemSeparator}
/>
That way, RenderItem is treated as a component and thus can use hooks.
I think problem is occurring due to setListState(!listState) with press. I suggest you to wrap your state changing method into a function. Because onPress accepts only function type but you are giving it a return statement from hooks.
const RenderList = ({data}) => {
return data.map((option, index) => {
return <Item title={option}/>
});
};
const Header = ({ title, style, press }) => (
<TouchableHighlight onPress={press}>
<Text style={style} >{title}</Text>
</TouchableHighlight>
)
const RenderItem = ( {item} ) => {
console.log(styles)
let dataToShow;
const [listState, setListState] = useState(true);
if (listState){
dataToShow = <RenderList data={item.data}/>
} else {
dataToShow = <Text/>
}
return (
<View style={styles.section}>
<Header
title={item.title}
style={styles.header}
press={()=>{
setListState(!listState)
}}
/>
{dataToShow}
</View>
)}
function Screen() {
const [lvls, setLvls] = React.useState([]);
const [done, setDone] = React.useState(null);
const [toggleCheckBox, setToggleCheckBox] = React.useState(false)
React.useEffect(() => {
async function checkData() {
const data = await AsyncStorage.getAllKeys();
setLvls(data);
}
checkData();
setDone(true);
}, []);
return (
<View>
{done && (lvls.length) ? (
lvls.map((element, i) => {
return (
<View key={i} style={{flexDirection: 'row'}}>
<CheckBox
disabled={false}
value={toggleCheckBox}
onValueChange={(newValue) => setToggleCheckBox(newValue)}
/>
<Text style={styles.text}>{lvls[i]}</Text>
</View>)
})
):
(
<Text style={styles.emptyText}>NO</Text>
)}
</View>
);
}
My aim is to dynamically render a checkbox that corresponds to each element in lvls.
I am currently doing that, however all of the checkboxes share the same state toggleCheckbox.
How can I create unique states for each checkbox according to lvls?
You can create a object that will store all the checkboxes values.
const [toggleCheckBox, setToggleCheckBox] = React.useState({})
<CheckBox
disabled={false}
value={toggleCheckBox[i] ? true : false}
onValueChange={() =>
setToggleCheckBox({
...toggleCheckBox,
[i] : !toggleCheckBox[i]
})}
/>
Placing into your code...
function Screen() {
const [lvls, setLvls] = React.useState([]);
const [done, setDone] = React.useState(null);
const [toggleCheckBox, setToggleCheckBox] = React.useState({})
React.useEffect(() => {
async function checkData() {
const data = await AsyncStorage.getAllKeys();
setLvls(data);
}
checkData();
setDone(true);
}, []);
return (
<View>
{done && (lvls.length) ? (
lvls.map((element, i) => {
return (
<View key={i} style={{flexDirection: 'row'}}>
<CheckBox
disabled={false}
value={toggleCheckBox[i] ? true : false}
onValueChange={() =>
setToggleCheckBox({
...toggleCheckBox,
[i] : !toggleCheckBox[i]
})}
/>
<Text style={styles.text}>{lvls[i]}</Text>
</View>)
})
):
(
<Text style={styles.emptyText}>NO</Text>
)}
</View>
);
}