React Native - Data is not loaded in the screen but if reload the page I am able to see the data - react-native

I am new to React Native.
I am storing the some data like GUID, userID, company name , in AsyncStorage when user login to the apps for the first time. I want to load the department details in department page based on selected company name which tag to unique GUID.
I am able to get the data from the AsyncStorage. Now I need to pass the GUID to "setDepartment(GUID)" store then pass to fetch API to get the data from server.
Problem : The data not able to load open when I open the department page but if I refresh the page , I am able to see the data in the screen. I am not sure where I make the mistakes. I think it something do with useEffect and useCallback. Please Guide Me. Thank You.
const DepartmentScreen = (props) => {
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(false);
const departments = useSelector((state) => state.departments.allDepartment);
const dispatch = useDispatch();
const [GUID, setGUID] = useState("");
const getData = useCallback(async () => {
try {
AsyncStorage.getItem("companyData").then((companyData) => {
let parsed = JSON.parse(companyData);
setGUID(parsed.GUID);
console.log(GUID);
});
} catch (error) {
console.log(error);
}
}, []);
useEffect(() => {
getData();
}, [dispatch, getData]);
const loadDepartment = useCallback(async () => {
setError(null);
setIsLoading(true);
try {
//getData();
await dispatch(departmentAction.setDepartment(GUID));
} catch (err) {
setError(err.message);
}
setIsLoading(false);
}, [dispatch, setIsLoading, setError]);
useEffect(() => {
loadDepartment();
}, [dispatch, loadDepartment]);
if (error) {
return (
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
<Text>
AN ERROR OCCURRED {error} + {GUID}
</Text>
<Button title="Reload" onPress={loadDepartment} />
</View>
);
}
if (isLoading) {
return (
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
<ActivityIndicator size="large" />
</View>
);
}
if (!isLoading && departments.length === 0) {
return (
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
<Text>NO DEPARTMENT FOUND</Text>
</View>
);
}
return (
<View style={{ flex: 1 }}>
<View style={styles.ButtonView}>
<View>
<Button title="Listed" />
</View>
<View>
<Button title="De-Listed" />
</View>
</View>
<FlatList
data={departments}
renderItem={(itemData) => (
<DepartmentItem
name={itemData.item.deptName}
code={itemData.item.deptCode}
/>
)}
keyExtractor={(item, index) => index.toString()}
/>
</View>
);
};

Related

Lodesh Filter is giving mid string data

I am new with React Native and facing issue with Lodesh Filter. It is giving mid-string data. Ex if I want to search Mitsubishi and start typing "mi" it will not give me mitsubishi but if I start type "sub" then it is giving me mitsubishi.
Below is my code:
import React, { useEffect, useState } from 'react';
import {View, Text, Button, TextInput, FlatList, ActivityIndicator, StyleSheet, Image} from 'react-native';
import filter from 'lodash.filter';
const CarList = () => {
const [isLoading, setIsLoading] = useState(false);
const [data, setData] = useState([]);
const [error, setError] = useState(null);
const [query, setQuery] = useState('');
const [fullData, setFullData] = useState([]);
useEffect(() => {
setIsLoading(true);
fetch(`https://myfakeapi.com/api/cars/?seed=1&page=1&results=20`)
.then(response => response.json())
.then(response => {
setData(response.cars);
setFullData(response.cars);
setIsLoading(false);
})
.catch(err => {
setIsLoading(false);
setError(err);
});
}, []);
if (isLoading) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<ActivityIndicator size="large" color="#5500dc" />
</View>
);
}
if (error) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text style={{ fontSize: 18}}>
Error fetching data... Check your network connection!
</Text>
</View>
);
}
const handleSearch = text => {
const formattedQuery = text.toLowerCase();
const filteredData = filter(fullData, user => {
console.log(contains(user, formattedQuery));
return contains(user, formattedQuery);
});
setData(filteredData);
setQuery(text);
};
const contains = ({ car, car_model,car_color }, query) => {
if (car.includes(query) || car_model.includes(query) || car_color.includes(query)) {
return true;
}
return false;
};
function renderHeader() {
return (
<View
style={{
backgroundColor: '#fff',
padding: 10,
marginVertical: 10,
borderRadius: 20
}}
>
<TextInput
autoCapitalize="none"
autoCorrect={false}
clearButtonMode="always"
value={query}
onChangeText={queryText => handleSearch(queryText)}
placeholder="Search"
style={{ backgroundColor: '#fff', paddingHorizontal: 20 }}
/>
</View>
);
}
return (
<View style={styles.container}>
<Text style={styles.text}>Favorite Contacts</Text>
<FlatList
ListHeaderComponent={renderHeader}
data={data}
keyExtractor={({ id }) => id}
renderItem={({ item }) => (
<View style={styles.listItem}>
<Image
source={{
uri: 'https://picsum.photos/200',
}}
style={styles.coverImage}
/>
<View style={styles.metaInfo}>
<Text style={styles.title}>{`${item.car} ${
item.car_model
}`}</Text>
</View>
</View>
)}
/>
</View>
);
}
Each car record have following fields:
{
"id": 1,
"car": "Mitsubishi",
"car_model": "Montero",
"car_color": "Yellow",
"car_model_year": 2002,
"car_vin": "SAJWJ0FF3F8321657",
"price": "$2814.46",
"availability": false
}
When you write mit, in contain function you are checking if(car.includes(text)...) but car name starts with an uppercase letter. You need to convert the car name in lowerCase before checking the text like this:
const contains = ({ car, car_model, car_color }, query) => {
if (car.toLowerCase().includes(query) || car_model.toLowerCase().includes(query) || car_color.toLowerCase().includes(query)) {
return true;
}
return false;
};

app crashes because of Flat-List API calling

I'm calling API and seeing the respective API values in the log, it shows me correct values, but when I try to set API in Flat list with the help of hooks my app crashes. I don't know the reason as I'm new in react native, so any help regarding this would be really appreciated.
NOTE( If I'm displaying the values directly without flat list it won't cause any error)
function Item({ item }) {
const navigation = useNavigation();
return (
<TouchableOpacity style={styles.listItemBox}
onPress={() => navigation.navigate('PatientDemographics')}
>
<View style={{flex:1}}>
<Text numberOfLines={1} style={{ textAlign: 'left', fontSize: 25, color:"#075430", textAlign: 'center',fontFamily:"Montserrat-Regular"}}>{item.firstName}</Text>
<TouchableOpacity style={[styles.smallRoundedBlueRoundedNoMargin,{marginTop:10,marginBottom:40}]}
onPress={() => navigation.navigate('PatientDemographics')} >
<Text style={[styles.cardText,{fontSize: 18},{color: 'white'}]}>SELECT </Text>
</TouchableOpacity>
</View>
</TouchableOpacity>
);
}
const SelectPatient = () => {
let numColumns = 4;
const formatData = (data, numColumns) => {
const numberOfFullRows = Math.floor(data.length / numColumns);
let numberOfElementsLastRow = 8 - (numberOfFullRows * numColumns);
while (numberOfElementsLastRow !== numColumns && numberOfElementsLastRow !== 0) {
data.push({ key: `blank-${numberOfElementsLastRow}`, empty: true });
numberOfElementsLastRow++;
}
return data;
};
// const navigation = useNavigation();
const [isLoading, setLoading] = useState(true);
const [patient, setPatient] = useState([]);
const mrnum=89
useEffect(() => {
axios({
method: 'get',
url: `https://emr-system.000webhostapp.com/emrappointment/emrappointment/patient/search?mrnum=89&cnic=&qrcode=`,
}).then((response) => {
//Balance / transaction-list
setPatient(response.data.result);
console.log(response.data.result);
console.log(patient[0].patientId);
}).then(() => setLoading(false));
}, []);
return (
<View style={styles.container}>
<Header name="Select Patient" class= ""/>
<UnitClerkHeader/>
<PatientHeader/>
<View style= {{flex:1 ,width: '100%', alignSelf: 'center'}}>
<SafeAreaView style={{flex:1}} >
<FlatList
style={{flex:1, marginTop: 30, marginRight:30,marginLeft:30}}
data={ formatData(patient,numColumns)}
renderItem={({ item }) => <Item item={item}/>}
keyExtractor={item => item.patientId}
numColumns = {numColumns}
/>
</SafeAreaView>
</View>
</View>
);
}
export default SelectPatient;
You can try with
<FlatList
style={{ flex: 1, marginTop: 30, marginRight: 30, marginLeft: 30 }}
data={() => formatData(patient, numColumns)}
renderItem={({ item }) => <Item item={item} />}
keyExtractor={item => item.patientId}
numColumns={numColumns}
/>
I can help you better when you show your error too.

Why is AsyncStorage not retrieving data once I refresh my App?

I am building a todo app and I am trying to store and retrieve data but it's not retrieving any data that is being stored. Once I refresh the data doesn't seem to persist. If there is another way of storing or writing my code please assist. I tried using other methods of storage like MMKV but it was just similar to AsyncStorage so I decided to stick with AsyncStorage. Here is my code:
import AsyncStorage from "#react-native-async-storage/async-storage";
export default function todaytodo() {
const [modalOpen, setModalOpen] = useState(false);
const [todos, setTodos] = useState("");
const storedata = async () => {
try {
await AsyncStorage.setItem("Todos", JSON.stringify(todos));
} catch (err) {
console.log(err);
}
};
const loadData = async () => {
try {
const value = await AsyncStorage.getItem("Todos");
if (value !== null) {
console.log(value);
return value;
}
} catch (error) {
console.log(error);
}
};
useEffect(() => {
storedata();
loadData();
});
const toggleComplete = (index) =>
setTodos(
todos.map((Todo, k) =>
k === index ? { ...Todo, complete: !Todo.complete } : Todo
)
);
const pressHandler = (key) => {
setTodos((prevTodos) => {
return prevTodos.filter((todo) => todo.key != key);
});
};
const submitHandler = (Todo) => {
Todo.key = Math.random().toString();
setTodos((currentTodo) => {
return [Todo, ...currentTodo];
});
setModalOpen(false);
};
return (
<View style={styles.container}>
<View>
<View>
<Ionicons
style={{
position: "absolute",
marginTop: 650,
alignSelf: "flex-end",
zIndex: 10,
marginRight: 5,
}}
name="md-add-circle-outline"
size={73}
color="black"
onPress={() => setModalOpen(true)}
/>
</View>
<FlatList
data={todos}
renderItem={({ item, index, complete }) => (
<TouchableOpacity onPress={() => toggleComplete(index)}>
<ScrollView>
<View style={styles.everything}>
<View style={styles.itemlist}>
<Checkbox
label="delete"
checked={true}
onPress={() => pressHandler(item.key)}
/>
<Text
style={{
marginLeft: 8,
marginTop: 5,
fontSize: 15,
textDecorationLine: item.complete
? "line-through"
: "none",
color: item.complete ? "#a9a9a9" : "black",
}}
>
{item.Todo}
</Text>
</View>
<Text
style={{
fontSize: 12,
marginLeft: 50,
marginTop: -15,
color: "#008b8b",
textDecorationLine: item.complete
? "line-through"
: "none",
color: item.complete ? "#a9a9a9" : "#008b8b",
}}
>
{item.Comment}
</Text>
</View>
</ScrollView>
</TouchableOpacity>
)}
/>
</View>
<View style={styles.modalcont}>
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<RNModal visible={modalOpen} animationType="slide">
<View style={styles.modalContent}>
<Ionicons
name="md-close-circle-outline"
style={{ alignSelf: "center" }}
size={60}
color="black"
onPress={() => setModalOpen(false)}
/>
<AddForm submitHandler={submitHandler} />
</View>
</RNModal>
</TouchableWithoutFeedback>
</View>
</View>
);
}
Use of useEffect is suspicious here, If you want to do it once on load of component
then need to update code for useEffect.
useEffect(() => {
storedata();
loadData();
}, []);

how make my hook valid ? Object are not valid as a react child

i'm doing my hook with firestore. I did praticly exactly the same on an ohter page and he works. But this one i have the error : Objects are not valid as a React child (found: object with keys {_U, _V, _W, _X}). If you meant to render a collection of children, use an array instead.
On my console i can see an empty array like that
cc []
also my hook
async function GetFriendsRequest() {
const [TeamsArray, updateTeamArray] = React.useState([]);
firestore()
.collection("Teams")
// Filter results
.where("uid", "==", await AsyncStorage.getItem("userID"))
.get()
.then((querySnapshot) => {
if (querySnapshot.empty) {
console.log("no documents found");
} else {
querySnapshot.forEach(async (doc) => {
let Teams = doc._data;
TeamsArray.length = 0;
updateTeamArray((arr) => [...arr, Teams]);
console.log("cc", JSON.stringify(TeamsArray));
});
}
});
return (
<View>
{TeamsArray.map((element, key) => {
<View style={{ flex: 1, flexDirection: "row" }}>
<View>
<Text style={{ color: "#5DC1D3" }}>
{element.MembersList.nickName}
</Text>
<Text style={{ color: "#5DC1D3" }}>{element.Activity} </Text>
</View>
</View>;
})}
</View>
);
}
Something is wrong ?
Your .map() callback isn't returning anything. You need to replace the braces with parentheses in the body of the callback in order to return your JSX:
{TeamsArray.map((element, key) => (
<View style={{ flex: 1, flexDirection: "row" }}>
<View>
<Text style={{ color: "#5DC1D3" }}>
{element.MembersList.nickName}
</Text>
<Text style={{ color: "#5DC1D3" }}>{element.Activity} </Text>
</View>
</View>;
))}
There's a few mistakes in your component, you'll have to fix those first before debugging.
// This is a component, not a hook, so use it like <GetFriendsRequest />
async function GetFriendsRequest() {
const [TeamsArray, updateTeamArray] = React.useState([]);
// This code was in the render loop
// put it inside a function so it doesn't run on every single render
const init = async () => {
const uid = await AsyncStorage.getItem("userID");
firestore()
.collection("Teams")
// Filter results
.where("uid", "==", uid)
.get()
.then((querySnapshot) => {
if (querySnapshot.empty) {
console.log("no documents found");
} else {
const results = [];
querySnapshot.forEach(async (doc) => {
let Teams = doc.data();
// Don't mutate react state, it should be treated as immutable
// TeamsArray.length = 0;
// This is an async function, but it's being
// called as if it were syncronous
// updateTeamArray((arr) => [...arr, Teams]);
results.push(Teams);
});
// Schedule a single state update
updateTeamArray([...results, ...TeamsArray]);
}
});
}
// Use an expression like this to debug
useEffect(() => {
// Log state every time it updates
console.log(TeamsArray);
}, [TeamsArray]);
useEffect(() => {
init();
}, []);
return (
<View>
{TeamsArray.map((element, key) => {
// Something has to be returned from this map
return <View style={{ flex: 1, flexDirection: "row" }}>
<View>
<Text style={{ color: "#5DC1D3" }}>
{element.MembersList.nickName}
</Text>
<Text style={{ color: "#5DC1D3" }}>{element.Activity} </Text>
</View>
</View>;
})}
</View>
);
};

Change border color text input When its empty in react native

I want when text input is empty change border color to red with press button:
const post = () => {
let list = [];
if (homeAge === '') {
list.push('homeage')
}
}
<TextInput
style={[Styles.TextInput, { borderColor: list.includes('homeage') ? 'red' : '#006d41' }]}
onChangeText={(event) => homeAgeHandler(event)}
/>
<Button style={Styles.Button}
onPress={() => post()}>
<Text style={Styles.TextButton}>ثبت اطلاعات</Text>
</Button>
Use a useRef hook :
const ref=useRef(0);
const post = () => {
let list = [];
if (homeAge === '') {
list.push('homeage')
}
}
useEffect(()=>{
if(list.size==0&&ref.current)
{
ref.current.style.borderColor = "red";
}
},[list,ref]);
<TextInput ref={ref}
onChangeText={(event) => homeAgeHandler(event)}
/>
<Button style={Styles.Button}
onPress={() => post()}>
<Text style={Styles.TextButton}>ثبت اطلاعات</Text>
</Button>
Here is a simple example to validate text and change styling based on validation,
const App = () => {
const [text, setText] = useState("");
const [error, setError] = useState(false);
const validateText = () => {
if (text === "") {
setError(true);
} else {
setError(false);
}
};
return (
<View>
<TextInput style={[Styles.TextInput, { borderColor: error ? 'red' : '#006d41', borderWidth:'1px'}]}
onChangeText={setText}
/>
<Button style={Styles.Button}
onPress={validateText}>
<Text style={Styles.TextButton}>ثبت اطلاعات</Text>
</Button>
</View>
);
};
export default App;
TextInput empty:
TextInput not empty:
Use state instead.
Also, In the given example, you are trying to access the list which is the local variable of the post() method.
Here is the alternate solution:
export default function App() {
const [homeAge, setHomeAge] = useState('');
return (
<View style={styles.container}>
<TextInput
value={homeAge}
style={[
styles.textInput,
{ borderColor: !homeAge ? 'red' : '#006d41' },
]}
onChangeText={(text) => setHomeAge(text)}
/>
<Button title={'ثبت اطلاعات'} style={styles.button} onPress={() => {}} />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
textInput: {
padding: 10,
borderWidth: 1,
},
});
Working example: Expo Snack