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>
);
}
Related
Im trying to make a feature for my app where the user can fill a questionnaire with radio buttons and he can save the progress and can return later to finish it.
Take a look at this code:
const Step3 = () => {
const [questions, setQuestions] = useState([]);
const [answers, setAnswers] = useState([]);
const {addQuest} = useContext(AuthContext);
const getQuestions = async () => {
const locale = 'sq'; // TODO: get current locale
const response = await apiStandarts.get(`/questions?locale=${locale}`, {
params: { _limit: MAX_QUESTIONS, active: 1, _sort:'sortId:ASC' },
});
setQuestions(response.data);
};
const isOptionSelected = (option) => {
const answer = answers[option.question]
if (answer) {
return option.id == answer.id
}
return false;
}
const saveData = () =>{
AsyncStorage.setItem('questions', JSON.stringify(answers)).then(() => {
console.log('data saved', answers)
}).catch((error) => {
console.log(error)
})}
const retrieveData = async () => {
try {
const answers = await AsyncStorage.getItem('questions');
const parsed = JSON.parse(answers);
Alert.alert(`${parsed.id}`);
} catch(error) {
Alert.alert(error)
}
}
useEffect(() => {
getQuestions();
}, []);
const OptionList = (groupOption) => {
return (
<FlatList
data={groupOption.options}
keyExtractor={(result) => result.id.toString()}
renderItem={({ item, index}) => {
const clickedRadio = () => {
const selectedOption = {[item.question]:{...item}}
setAnswers({...answers, ...selectedOption})
console.log(answers)
}
const status = isOptionSelected(item) ? true : false
return (
<View key={index}>
<Radio initialValue={status} label={item.description} onChange={() => clickedRadio()}/>
</View>
);
}}
/>
);
};
return (
<View style={styles.container}>
<Text style={{ fontWeight: "bold", fontSize: 16, color: "#6B24AA" }}>
{t("Choose an option/Scroll for more questions")}
</Text>
<FlatList
data={questions}
keyExtractor={(result) => result.id.toString()}
renderItem={({ item, index }) => {
return (
<View style={styles.groupOptions} key={index}>
<Text>{item.description}</Text>
<OptionList options={item?.question_options}></OptionList>
</View>
);
}}
/>
<Button onPress={() => addQuest({answers})}>Save progress</Button>
<Button onPress={() => retrieveData()}>Get progress</Button>
</View>
)
}
I've tried with AsyncStorage but i get my questions from an API and the data re-renders every time the app opens again. Any ideas how to achieve this ? Thanks in advance
I'm using react native to create a simple to-do app using Firebase. I used the firestore database. I am able to push the data into Firebase using user inputs. I also tried fetching the data in my screen but I cannot see the data.
dashboard.js ( I want the list of data to be shown here)
export default function Dash(){
const [task, setTask] = useState();
const [taskItems, setTaskItems] = useState([]);
const [loading, setLoading] = useState(true);
const todoCollection = db.collection('todos');
useEffect(() => {
return todoCollection.onSnapshot((querySnapshot) =>{
const list=[];
querySnapshot.forEach(doc => {
const {text, done} = doc.data();
list.push({
id: doc.id,
text,
done,
});
});
setTask(list);
if (loading) {
setLoading(false);
}
});
}, [])
async function addTask() {
await todoCollection.add({
text:task,
done: false,
}).then(()=> {
alert ("Task added Succesfully")
})
setTask('');
Keyboard.dismiss();
setTask(null);
}
const handleTask =()=>{
Keyboard.dismiss();
setTaskItems([...taskItems, task])
setTask(null);
}
const deleteTask = (index) => {
let itemsCopy = [...taskItems];
itemsCopy.splice(index,1);
setTaskItems(itemsCopy);
}
if (loading) {
return null;
}
return(
<>
<View style = {styles.tasksWrapper}>
<Text style={styles.sectionTitle} > ToDos List </Text>
<View style={{height:30}}></View>
<View style = {styles.items}>
{/* {
taskItems.map((item, index)=> {
return(
<Task text={item} del={deleteTask} i={index} />
)
})
} */}
<FlatList
style={{flex: 1}}
data={task}
keyExtractor={(item) => item.id}
renderItem={({ item }) => <Todo {...item} />}
/>
</View>
</View>
<KeyboardAvoidingView behavior={Platform.OS ==="ios"? "padding": "height"}
style={styles.writeTaskWrapper}>
<TextInput style={styles.input} placeholder={'write a task'} value={task} onChangeText={text => setTask(text)}/>
<TouchableOpacity onPress={()=>addTask()}>
<View style={styles.addWrapper}>
<Text style={styles.addText}> + </Text>
</View>
</TouchableOpacity>
</KeyboardAvoidingView>
</>
)
}
Todo.js
import React from 'react';
import {db} from '../firebase/fire';
import { List } from 'react-native-paper';
function Todo({ id, text, done }) {
async function toggleComplete() {
await db
.collection('todos')
.doc(id)
.update({
done: !done,
});
}
return (
<List.Item
text={text}
onPress={() => toggleComplete()}
left={props => (
<List.Icon {...props} icon={done ? 'check' : 'cancel'} />
)}
/>
);
}
export default React.memo(Todo);
The app shows no error but the list is not rendering.
I'm trying to display a bunch of data i have on firebase in a flatlist, I don't really know where the problem is right now, i've tried physically filling the array out and that works but it doesn't when i get the data from firebase. I do see that im getting the data on the console log but it's not getting displayed.
function Squad() {
const gk = [];
db.collection('squad').orderBy('position').get().then(snapshot => {
snapshot.forEach(doc => {
const playerObject = doc.data();
gk.push({name: playerObject.name, number: playerObject.number});
console.log(gk);
});
});
const Item = ({ name, number }) => (
<View style={styles.item}>
<Text style={styles.itemText}>{number} - {name}</Text>
</View>
);
const renderItem = ({ item }) => (
<Item name={item.name} number={item.number} />
)
return(
<View>
<View style={styles.bar}>
<Text style={styles.barText}>goalkeeper</Text>
</View>
<FlatList
data={gk}
renderItem={renderItem}
keyExtractor={item => item.id}
/>
</View>
)
}
You can get the info on mount in an async function, then store it in a stateful array using hooks.
function Squad() {
const [gk, setGk] = useState([]);
const getSquad = async () => {
const ref = db.collection('squad').orderBy('position');
const doc = await ref.get();
const playerObject = doc.data();
const newGk = [...gk, {name: playerObject.name, number: playerObject.number}];
setGk(newGk);
}
useEffect(() => {
getSquad();
}, [])
const Item = ({ name, number }) => (
<View style={styles.item}>
<Text style={styles.itemText}>{number} - {name}</Text>
</View>
);
const renderItem = ({ item }) => (
<Item name={item.name} number={item.number} />
)
return(
<View>
<View style={styles.bar}>
<Text style={styles.barText}>goalkeeper</Text>
</View>
<FlatList
data={gk}
renderItem={renderItem}
keyExtractor={item => item.id}
/>
</View>
)
}
Start by creating a useEffect hook to act as a componentWillMount function to call the method when the compnent is ready. I have also included catch block in order to show any errors that might occur.
import React, { useState, useEffect } from "react";
const Squad = () => {
const [gk, setGK] = useState([]);
useEffect(() => {
getSquadData();
});
const getSquadData = () => {
db.collection("squad")
.orderBy("position")
.get()
.then((snapshot) => {
let myData = [];
snapshot.forEach((doc) => {
const playerObject = doc.data();
myData.push({
id: playerObject.id,
name: playerObject.name,
number: playerObject.number,
});
});
setGK(myData);
})
.catch((error) => {
console.log("Error getting data: ", error);
});
};
const Item = ({ name, number }) => (
<View style={styles.item}>
<Text style={styles.itemText}>
{number} - {name}
</Text>
</View>
);
const renderItem = ({ item }) => (
<Item name={item.name} number={item.number} />
);
return (
<View>
<View style={styles.bar}>
<Text style={styles.barText}>goalkeeper</Text>
</View>
<FlatList
data={gk}
renderItem={renderItem}
keyExtractor={(item) => item.id}
/>
</View>
);
};
export default Squad;
So if you are seeing error logs in your console, check your collection in firestore, and also check the rules in your firestore.
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>
);
}
I am calling the contactsfunction from the main return. I don't see any error until here:
const showContacts = React.useCallback(
(data: UsersQueryHookResult) => {
if (data) {
return (
<View style={styles.users}>
</View>
);
}
},
[userData],
);
const contacts = () => {
console.log('running');
const { loading, error, data } = useUsersQuery({
variables: {
where: { id: 34 },
},
});
console.log('DATA COMING', data);
//setUserData(data);
//console.log('contact name', data.users.nodes[0].userRelations[0].relatedUser.firstName);
};
return (
<SafeAreaView style={{ flex: 1 }}>
<Container style={{ flex: 1, alignItems: 'center' }}>
<Item style={styles.addToWhitelist}>
<Icon
name="add"
onPress={() => navigation.navigate('AddContactTry')}
/>
<Text style={styles.addToContactTitle}>Add contact</Text>
</Item>
<Text onPress={() => navigation.navigate('Home')}>Zurück</Text>
<View style={{ width: moderateScale(350) }}>
<Text>Keine Kontacte</Text>
</View>
{contacts()}
</Container>
</SafeAreaView>
);
};
Now I want to do some conditional rendering on the basis of the results from contacts. However, as soon as I uncomment setUserData(data); I get an error that too many re-renders. I don't get what I am doing wrong in showUsersto get this error.
Edit:
I tried this but it gives an invalid hook call error:
export const Whitelist: React.FunctionComponent = (props) => {
const [userData, setUserData] = useState<UsersQueryHookResult>('');
useEffect(() => {
// Your function to fetch/get contacts
const data = contacts();
setUserData(data);
}, [])
const showContacts = React.useCallback(
(data: UsersQueryHookResult) => {
if (data) {
return (
<View style={styles.users}>
</View>
);
}
},
[userData],
);
const contacts = () => {
console.log('running');
const { loading, error, data } = useUsersQuery({
variables: {
where: { id: 34 },
},
});
console.log('DATA COMING', data);
//setUserData(data);
};
return (
<SafeAreaView style={{ flex: 1 }}>
<Container style={{ flex: 1, alignItems: 'center' }}>
<Item style={styles.addToWhitelist}>
<Icon
name="add"
onPress={() => navigation.navigate('AddContactTry')}
/>
<Text style={styles.addToContactTitle}>Add contact</Text>
</Item>
<Text onPress={() => navigation.navigate('Home')}>Zurück</Text>
{/* {contacts()} */}
</Container>
</SafeAreaView>
);
};
Try to fetch contacts in componentDidMount method or useEffect (in your case with hooks) and store the result in a state with useState.
const [contacts, setContacts] = React.useState(null);
[...]
React.useEffect(() => {
// Your function to fetch/get contacts
const data = contacts();
setContacts(data);
}, [])
[...]
return (
<SafeAreaView style={{ flex: 1 }}>
[...]
{contacts && contacts.map(contact => (<View>{contact.name}</View>)}
[...]
</SafeAreaView>
);
hope it helps.