Reputation: 289
I'm trying to fetch a list of departments from an URL in a React Native application
export default function App() {
var [department,setDepartment]=useState([])
const token = /* my token here */
const getDepartments=()=>{
const url = /*my api's url here*/
return fetch(url, {
method: 'GET',
headers: { "Authorization": "Bearer" + token ,
'Accept': 'application/json',
'Content-Type':'application/json'
}
})
.then(response => response.json())
.catch(error => console.error(error))
}
const getdepartment = async () => {
await getDepartments().then((res) => {
console.log('res',res)
res.map((p, key) => {
setDepartment([...department,department.push({
name: p.name,
id: p.id,
})])
});
});
console.log(department[0].name) //displays the correct value
};
return (
<View>
<Button
onPress={()=>getdepartment()}
title="Learn More"
color="#841584"
accessibilityLabel="Learn more about this purple button"
/>
<Text>{department[0].name}</Text> //here lays the problem
</View>
)
}
here department[0] in JSX is undefined despite the getdepartment() function returning correct department[0]
Upvotes: 0
Views: 1745
Reputation: 261
First the UI gets rendered and at that moment the department is empty and trying to fetch the name throws error. You can have the check as below
{department!=null && department.length>0 && department[0].name!=null &&
<Text>{department[0].name}</Text>
}
Upvotes: 0
Reputation: 2422
You should change
res.map((p, key) => {
setDepartment([...department,department.push({
name: p.name,
id: p.id,
})])
to
setDepartment(res.map((p,key)=>({name:p.name, id:p.id})))
Upvotes: 0
Reputation: 8718
Your problem is that your department
state variable will be an empty array until your asynchronous call has succeeded and replaced it with actual data.
You should display some kind of loading indicator until the data is available:
return <View>
<Button
onPress= {() => getdepartment()}
title = "Learn More"
color = "#841584"
accessibilityLabel = "Learn more about this purple button"
/>
{department.length
? department.map(d => <Text key={d.id}>{d.name}</Text>)
: <Text>Loading departments...</Text>}
</View>;
I've also made it display a <Text>
tag for every department once it does have the data.
The second problem is your array initialization:
setDepartment([...department, department.push({
name: p.name,
id: p.id,
})])
You're adding the result of department.push
to your array, which is a number. You want to add the object directly:
setDepartment([...department, {
name: p.name,
id: p.id,
}])
Upvotes: 0
Reputation: 942
getdepartment
its called after the first render happens. So before you press the button "Learn More" department
is an empty array
Try this:
<Text>{(department.length > 0)? department[0].name : ""}</Text>
Upvotes: 1
Reputation: 417
I think there is some misuse of states and arrays in your case, please check the usages of arrays with states and how to update them.
const [theArray, setTheArray] = useState(initialArray);
setTheArray([...theArray, newElement]);
Upvotes: 1