Reputation: 546
I am making an axios call in the render of my react native app.
render() {
return (
<View style={{flex: 1, backgroundColor: 'white'}}>
<ScrollView
style={styles.scrollView}
contentContainerStyle={{justifyContent: 'center'}}>
<Text style={styles.heading}>Checked Out Books</Text>
{this.state.books.map((book) => {
axios
.get('http://localhost:3000/books/id/' + book)
.then((res) => {
console.log(res.data);
return (
<View>
<Image
source={{uri: res.data.cover}}
height={150}
width={110}></Image>
<Text>{res.data.title}</Text>
</View>
);
})
.catch((err) => {
console.log(err);
alert('Something went wrong.');
});
})}
When the call finishes and it gets to the return step, nothing is returned.
I don't know why this is happening. This segment of code is not returned:
<View>
<Image
source={{uri: res.data.cover}}
height={150}
width={110}></Image>
<Text>{res.data.title}</Text>
</View>
Why is this?
Upvotes: 1
Views: 143
Reputation: 42228
Per the comment that you are not returning anything from .map()
, an arrow function either needs to have no brackets like (book) => axios.get(
or have brackets and use the word return
like (book) => { return axios.get(
.
The return
statement that you are looking at with the <View>
element is the return
for the .then()
callback function, not for the whole .map()
function.
But this is not going to solve your issue because the value that you would be returning from the .map()
is a Promise
, which is not something that you can print out in your component JSX.
@jamielarchin is correct that you cannot do data fetching inside your render()
method. It needs to be inside of a lifecycle method like componentDidMount
or componentDidUpdate
or inside of a useEffect
hook. Since you are just learning, I recommend that you learn with the most current approach which is to use a function component and useEffect
.
I recommend that you handle the data fetching for each book in a separate Book
component rather than dealing with fetching data in a loop. This is much simpler and it avoids having to refetch the entire list if just one book changes.
You can make that Book
component be a function component and keep your current "list of books" component as a class component.
// the book id is the only prop
const Book = ({ id }) => {
const [isError, setIsError] = useState(false);
const [isLoading, setIsLoading] = useState(false);
// save the book data here, once loaded
const [data, setData] = useState();
useEffect(
() => {
setIsLoading(true);
axios
.get('http://localhost:3000/books/id/' + id)
.then((res) => setData(res.data))
.catch((err) => setIsError(true))
.finally(() => setIsLoading(false));
},
[id] // dependency on the book id
);
if (data !== undefined) {
return (
<View>
<Image source={{ uri: data.cover }} height={150} width={110}></Image>
<Text>{data.title}</Text>
)}
</View>
);
}
// can show loading and error components too
// but for now I'm just returning nothing
return null;
};
render() {
return (
<View style={{flex: 1, backgroundColor: 'white'}}>
<ScrollView
style={styles.scrollView}
contentContainerStyle={{justifyContent: 'center'}}>
<Text style={styles.heading}>Checked Out Books</Text>
{this.state.books.map((book) => <Book id={book} key={book}/>)}
Upvotes: 1
Reputation: 72
You shouldn't make an axios call inside render (it is possible with some adjustments however it is not a good practice). You should either use hooks (like useEffect) if you are in a functional component or use componentDidMount if you are in a class component (which I assume you are). Examples are shown below.
class App extends React.Component {
constructor(){
this.state = {
bookIds: [], //You would fill this beforehand
books: [],
}
}
componentDidMount(){
for(let i = 0; i < bookIds; i++){
axios.get('http://localhost:3000/books/id/' + bookIds[i]).then((res) => {
books.push(res);
}.catch((err) => {
console.log(err);
alert('Something went wrong.');
});
}
}
render() {
return(
<View style={{flex: 1, backgroundColor: 'white'}}>
<ScrollView
style={styles.scrollView}
contentContainerStyle={{justifyContent: 'center'}}>
<Text style={styles.heading}>Checked Out Books</Text>
{this.state.books.map((book) => {
return (
<View>
<Image
source={{uri: book.data.cover}}
height={150}
width={110}>
</Image>
<Text>{book.data.title}</Text>
</View>
);
})
}
);
}
}
Would recommend you take a look at this: https://reactjs.org/docs/state-and-lifecycle.html.
There might be some issues with the brackets, Have a great day!
Upvotes: 0
Reputation: 1
Data fetching should be done from a lifecycle method for class components. You probably want to use componentDidMount: https://reactjs.org/docs/react-component.html#componentdidmount
Upvotes: 0