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

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>
);
};

Related

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

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>
);
};

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();
}, []);

In React Native can I setState to an object that is in an api call?

This should be something so incredibly easy, but I'm struggling really hard on this. All I want to do is setState of id to "results.id" from my api call. Once it changes the state to what is inside of the api, I will then be able to successfully open up the filmography api. I've tested the axios fetch url by putting in a real id, and it works. So I'm basically trying to grab the id that I get from a search, and update the id state with THAT id. If I'm trying to setState in the wrong function, then by all means help me get it in the right function! (Also I know I have some sloppy code, but a lot of it is personal notes for me until I'm ready to save it for good)
import React, { useState } from "react";
import {
View,
TextInput,
Button,
Text,
ActivityIndicator,
ScrollView,
Image,
TouchableHighlight,
Alert,
} from "react-native";
import Modal from "react-native-modal";
import axios from "axios";
export default function Screen4() {
// id is a 2 digit number for specific actor const apiurl5 = "http://api.tmdb.org/3/search/person?api_key=84c329a92566be57845322a19ff707ac&query=" const apiurl4 = "/movie_credits?api_key=84c329a92566be57845322a19ff707ac&language=en-US" const apiurl3 = "https://api.themoviedb.org/3/person/" const apiurl2 = "https://api.themoviedb.org/3/movie/upcoming?api_key=84c329a92566be57845322a19ff707ac&language=en-US&page=1"; const apiurl = "http://www.omdbapi.com/?apikey=7ad73765&"; const [state, setState] = useState({ s: "Enter an actor...", id: "", results: [], selected: [], modalVisible: false, modalVisible2: false });
const search = () => {
// apiurl + "&t=" + state.s (Single Result)
// apiurl + "&s=" + state.s (Multiple Results)
axios(apiurl5 + state.s).then(({ data }) => {
//let results = [data]; ----- ******** Use this for &t= **************** -------------
//let results = data.Search; ----- ******** Use this for &s= **************** -------------
let results = data.results;
let id = state.id;
setState((prevState) => {
return { ...prevState, modalVisible: true };
}),
setState((prevState) => {
return { ...prevState, results: results };
}),
setState((prevState) => {
return { ...prevState, id: id };
}),
Alert.alert("The ID is: ", id, [
{ text: "Close", onPress: () => console.log("alert closed") },
]);
});
};
const openPopup = () => {
axios(apiurl3 + state.id + apiurl4).then(({ data }) => {
let result = data.cast;
setState((prevState) => {
return { ...prevState, modalVisible2: true };
}),
setState((prevState) => {
return { ...prevState, selected: result };
});
});
};
return (
<View style={{ flex: 1, padding: 10, justifyContent: "center" }}>
<Text>Cinemaster!</Text>
<TextInput
style={{
borderBottomWidth: 1,
borderBottomColor: "#ff0000",
marginBottom: 20,
}}
onChangeText={(text) =>
setState((prevState) => {
return { ...prevState, s: text };
})
}
onSubmitEditing={search}
value={state.s}
/>
<Button onPress={search} title="Search"></Button>
{/* key=result.imdbID -
This gives multiple search results with the &s= is in the URL
key=result -
This gives the result with the &t= is in the URL */}
<Modal
//animationType="slide"
transparent={false}
//visible={(state.modalVisible)}
animationIn="slideInRight"
animationOut="slideOutLeft"
useNativeDriver={true}
isVisible={state.modalVisible}
>
<ScrollView>
{state.results.map((results, index) => (
<TouchableHighlight key={index}>
<View style={{ flex: 1, padding: 10, justifyContent: "center" }}>
<Button title="Full Filmography" onPress={openPopup}></Button>
<Text>Gender: {results.gender}</Text>
<Text>ID: {results.id}</Text>
{results.known_for.map((k, i) => (
<TouchableHighlight
key={i}
// onPress={() => openPopup()}
>
<View>
<Text>Title: {k.title}</Text>
<Image
source={{
uri:
"https://image.tmdb.org/t/p/original/" +
k.poster_path,
}}
style={{ width: 300, height: 500 }}
resizeMode="cover"
/>
</View>
</TouchableHighlight>
))}
{/* <Text>Title: {results.gender}</Text> -----THIS ALSO WORKS----- */}
{/* {dataItems.map((item, index) => (
<div key={index}>
<h1>{item.title}</h1>
{item.content.map((c, i) => (
<div key={i}>
<img src={c.imageUrl} />
<h3>{c.title}</h3>
<h3>{c.description}</h3>
<hr />
</div>
))}
</div>
))} */}
</View>
</TouchableHighlight>
))}
<Text
onPress={() =>
setState((prevState) => {
return { ...prevState, modalVisible: false };
})
}
style={{
marginTop: 50,
color: "red",
fontSize: 40,
fontWeight: "bold",
}}
>
Close!
</Text>
</ScrollView>
</Modal>
{/* animationType in Modal can be fade, none, or slide */}
<Modal
//animationType="slide"
transparent={false}
//visible={(state.modalVisible)}
animationIn="slideInRight"
animationOut="slideOutLeft"
useNativeDriver={true}
isVisible={state.modalVisible2}
>
<ScrollView>
{state.selected.map((cast, index2) => (
<View key={index2}>
<Text>Title:{cast.title} </Text>
<Text>Overview:{cast.overview} </Text>
</View>
))}
</ScrollView>
<TouchableHighlight
onPress={() =>
setState((prevState) => {
return { ...prevState, modalVisible2: false };
})
}
>
<Text
style={{
marginTop: 50,
color: "red",
fontSize: 40,
fontWeight: "bold",
}}
>
Close!
</Text>
</TouchableHighlight>
</Modal>
</View>
);
}
API for results.id :
http://api.tmdb.org/3/search/person?api_key=84c329a92566be57845322a19ff707ac&query=tom%20hanks
API for filmography:
https://api.themoviedb.org/3/person/31/movie_credits?api_key=84c329a92566be57845322a19ff707ac&language=en-US
Attached an image, showing the ID I'm trying to setState inPhoneExample
I figured it out. I had to use a for loop in order to get the data I needed in order to then set that data. What wasn't clear to me at first, was if that was necessary or not, and if it was I assumed I had to do that in the section of my code where I was mapping things. But no, once I got a for loop going in that search function it started to make sense to me.

React Native TypeError: undefined is not a function (near '...this.state.clubs.map...')

I am having trouble displaying my api data in the app, i feel like it has something to do with the way i want to map the data.
When i use my 1st api it works but it is not the right one because it shows all the clubs info not a single club.
Here is the postman:
Here is the console:
This is what is displays in the app:
The problem I am having is that when i use my 2nd api link that allows me to get a single clubs data i get an error when mapping it.
Here is my code, the only thing i changed was the api link, I also tried to use c.club.numberOfCheckIns but it didnt work either.
class Profile extends React.Component {
constructor(props) {
super(props)
this.state = {
clubInfo: []
};
}
componentDidMount() {
this._get('http://ec2-3-15-176-119.us-east-2.compute.amazonaws.com:8080/clubs/get/1').then(
data => {
this.setState({ clubInfo: data })
}
)
}
_get = async (endpoint) => {
const res = await fetch(endpoint, {
headers: {
'Content-Type': 'application/json',
'Access-Token': '1*adminaccesstoken'
}
})
const data = await res.json();
console.log(data)
return data;
}
renderClubData() {
return this.state.clubInfo.map((c, index) => {
const { clubId, name, city, country, email, verified } = c //destructuring
return (
<View key={c.clubId}>
<Text
bold
size={20}
color="#B8AA5B"
style={{ marginBottom: 4 }}
>{c.numberOfCheckIns}
</Text>
</View>
)
})
}
render() {
return (
<Block flex style={styles.profile}>
<Block flex>
<ImageBackground
source={{ uri: Images.EventPhoto }}
style={styles.profileContainer}
imageStyle={styles.profileBackground}
>
<ScrollView
showsVerticalScrollIndicator={false}
style={{ width, marginTop: '55%' }}
>
<Block flex style={styles.profileCard}>
<Block style={styles.info}>
<Block middle style={{ marginTop: 10, paddingBottom: 10 }} row space="between">
<Block middle>
{this.renderClubData()}
<Text size={12}>CHECK-INS</Text>
</Block>
Here is the postman:
I figured it out:
componentDidMount() {
this._get('API').then(
data => {
this.setState( {clubInfo: [data]})
}
)
}
renderClubData() {
return this.state.clubInfo.map((c, index) => {
return (
<View key={c.club.clubId}>
<Text bold size={20} color="#B8AA5B" style={{ marginBottom: 4 }} >
{c.club.numberOfCheckIns}
</Text>
</View>
)
})
}
I used [] for data to turn the JSON into an array.
The problem is the way you handle this.state.clubInfo.map() method. In order to use map method, you need to pass an array.
That is why it is worked previously because you send an array of data to this.state.clubInfo.map().
Change your renderClubData() as below because now you are getting an object as a result of the API request.
renderClubData() {
return (
<View key={c.clubId}>
{
this.state.clubInfo.club.numberOfCheckIns &&
<Text bold size={20} color="#B8AA5B" style={{ marginBottom: 4 }}>
{this.state.clubInfo.club.numberOfCheckIns}
</Text>
}
</View>
)
}
#DevAS is also right. you can try [this.state.clubInfo].map() as below,
renderClubData() {
return [this.state.clubInfo].map((c, index) => {
return (
<View key={c.club.clubId}>
<Text bold size={20} color="#B8AA5B" style={{ marginBottom: 4 }} >
{c.club.numberOfCheckIns}
</Text>
</View>
)
})
}
I hope this will helps you.

Get the input data from TextInputs which are programatically added using a button

I've a screen where there is a button to add textInputs. Any no. of inputs can be added by the user. There is another button named submit. When it is tapped, how can I get the appropriate input values. I need them in array eg: [{name1, designation1}, {name2, designation2}, ...].
Code:
App.js
export default class App extends React.Component {
state = {
myArr: []
}
_onPressOut() {
let temp = index ++
this.state.myArr.push(temp)
this.setState({
myArr: this.state.myArr
})
}
_getData() {
//how can I get the data from input values here?
}
render() {
let Arr = this.state.myArr.map((a, i) => {
return <NewComponent />
})
return (
<ScrollView>
<View style={styles.container}>
<Text>Event 1st</Text>
{ Arr }
<Text>Eventlast</Text>
</View>
<TouchableOpacity onPress={() => this._onPressOut()}>
<Text style={{ color: 'green' }}>Add New Component</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => this._getData()}>
<View style={{ backgroundColor: 'blue', marginTop: 30 }}>
<Text style={{ color: 'white', textAlign: 'center', marginVertical: 10 }}>Submit</Text>
</View>
</TouchableOpacity>
</ScrollView>
);
}
}
NewComponent.js
class NewComponent extends React.Component{
state = {
name: '',
designation: '',
}
onNameChange = (text) => {
this.setState({
name: text,
});
}
render () {
return (
<View style={{ borderTopWidth:2, borderBottomColor: 'red', paddingTop: 20, marginTop: 30 }}>
<TextInput
placeholder={'Enter Your Name'}
onChangeText={text => {
this.onNameChange(text);
// this.onPropValueChange('SignUpName', text);
}}
value={this.state.name}
style={[{borderBottomColor:'red', borderBottomWidth: 1}]}
/>
<TextInput
placeholder={'Designation'}
onChangeText={text => {
this.onDesignationChange(text);
// this.onPropValueChange('SignUpDesignation', text)
}
}
value={this.state.designation}
style={[{borderBottomColor:'red', borderBottomWidth: 1}]}
/>
</View>
);
}
}
Considering the following assumptions that,until the name is filled,the designation cannot be filled and until the one set of name and designation are filled, the next set of inputs should not be rendered,
In NewComponent.js for the destinationTextInput, make the following changes.
<TextInput
placeholder={'Designation'}
onChangeText={text => {
this.onDesignationChange(text);
// this.onPropValueChange('SignUpDesignation', text)
}
}
value={this.state.designation}
style={[{borderBottomColor:'red', borderBottomWidth: 1}]}
onBlur = {() => {this.props.onNameAndDesignationAdded(this.state.name,this.state.designation)}}
/>
And in App.js add the following
in state object, introduce a new state called resultArr as follows:
state = {
myArr: [],
resultArr : []
}
The _getData function will be as follows:
_getData(name,designation) {
//how can I get the data from input values here?
if(name,designation) {
let tempArr = this.state.resultArr;
tempArr.push({name, designation})
this.setState({resultArr : tempArr})
}
}
The NewComponent called in App.js will have a callback from the TextInput of destination input onBlur method.
let Arr = this.state.myArr.map((a, i) => {
return <NewComponent onNameAndDesignationAdded = {(name,designation) => {
this._getData(name,designation)
} } />
})