After making an api request and getting the data in searchbar.js component, I passed the data to another component (ShowList.js). But I was not able to map over the data.
Searchbar.js
import React from 'react'
import Button from 'react-bootstrap/Button';
import Form from 'react-bootstrap/Form';
import ShowsList from './ShowsList'
import { useState } from 'react'
import axios from 'axios';
const Searchbar = () => {
const [searchText, setSearchText] = useState('');
const [showData, setShowData] = useState([]);
async function handleSearch(e) {
e.preventDefault()
const config = { params: { q: searchText } };
const response = await axios.get(`https://api.tvmaze.com/search/shows?q=`, config);
setShowData(response.data);
showData.map(singleShow => {
console.log(singleShow)
})
}
return (
<div>
<Form>
<Form.Group className="mb-3" controlId="formBasicEmail">
<Form.Label>Tv Show: </Form.Label>
<Form.Control type="text" placeholder="Search TV show" onChange={(e) => setSearchText(e.target.value)} />
</Form.Group>
<Button variant="primary" onClick={handleSearch}>
Search
</Button>
</Form>
<ShowsList showData={showData} />
</div>
)
}
export default Searchbar
Output for Searchbar.js component
ShowList.js
import React from 'react'
const ShowsList = ({showData}) => {
showData.map(singleShow => {
console.log(singleShow)
})
return (
<>ShowList</>
)
}
export default ShowsList
Output after mapping over the same data array in ShowList.js component
ShowList.js
There is no problem in accessing the data without mapping.
import React from 'react'
const ShowsList = ({showData}) => {
console.log(showData)
return (
<>ShowList</>
)
}
export default ShowsList
Data accessing without mapping
CodePudding user response:
React does not work like that, if you make a console.log(showData) right after the setShowData(response.data); you will see the value remains the same, this is because the state is actually set after you leave the current function where you call the setState, if you think about it, it has a lot of sent.
The way you can achieve this is either maping the response.data directly or using useEffect hook for this particular state, something like this:
import React from 'react'
import Button from 'react-bootstrap/Button';
import Form from 'react-bootstrap/Form';
import ShowsList from './ShowsList'
import { useState, useEffect } from 'react'
import axios from 'axios';
const Searchbar = () => {
const [searchText, setSearchText] = useState('');
const [showData, setShowData] = useState([]);
async function handleSearch(e) {
e.preventDefault()
const config = { params: { q: searchText } };
const response = await axios.get(`https://api.tvmaze.com/search/shows?q=`, config);
setShowData(response.data);
}
//triggered after set and rendered showData
useEffect(() => {
showData.map(singleShow => {
console.log(singleShow)
})
},[showData])
return (
<div>
<Form>
<Form.Group className="mb-3" controlId="formBasicEmail">
<Form.Label>Tv Show: </Form.Label>
<Form.Control type="text" placeholder="Search TV show" onChange={(e) => setSearchText(e.target.value)} />
</Form.Group>
<Button variant="primary" onClick={handleSearch}>
Search
</Button>
</Form>
<ShowsList showData={showData} />
</div>
)
}
export default Searchbar
CodePudding user response:
the error shows that you are trying to invoke a map function on an undefined value, you can try to set a default value to the showData
props to make sure it is an array if it is undefined
import React from 'react'
const ShowsList = ({ showData = [] }) => {
showData.map(singleShow => {
console.log(singleShow)
})
return (
<>ShowList</>
)
}
export default ShowsList