My api data is being successfully passed from my api call into the table component but is not being rendered.
If after searching for a playlist I go in and make an edit to the table.js file the data will render correctly. App.js...
const App = (props) => {
const [playlists, setPlaylists] = useState([])
const [searchString, setSearchString] = useState() //use instead of onsubmit
const isFirstRef = useRef(true);
const search = (value) => {
setSearchString(value)
}
useEffect(
() => {
if (isFirstRef.current) {
isFirstRef.current = false;
return;
}
let spotlist = Spotify.playlistsearch(searchString)
let tablelist = []
spotlist.then(val =>{
val.forEach(element =>{
tablelist.push(
{
name: element.description,
track_count: element.tracks.total,
})
}
)})
setPlaylists(tablelist)
}, [searchString] );
return (
<div className="App">
<Searchform search={search}/>
<Table playlists={playlists}/>
</div>
)
};
The playlists prop is being shown as present under the PlayListTable component inspector but is not rendering. I am able to get the data to render IF I edit the file after seeing the data present in the component inspector. Table.js
import React from 'react'
import { Icon, Label, Menu, Table } from 'semantic-ui-react'
const PlayListTable = ({ playlists }) => {
return(
<Table celled>
<Table.Header>
<Table.Row>
<Table.HeaderCell>Playlist</Table.HeaderCell>
<Table.HeaderCell>Track Count</Table.HeaderCell>
</Table.Row>
</Table.Header>
<Table.Body>
{playlists.map( (playlist) => {
return (
<Table.Row>
<Table.Cell>
{playlist.name}
</Table.Cell>
<Table.Cell>
{playlist.track_count}
</Table.Cell>
</Table.Row>
)
}
)
}
</Table.Body>
<Table.Footer>
<Table.Row>
<Table.HeaderCell colSpan='3'>
<Menu floated='right' pagination>
<Menu.Item as='a' icon>
<Icon name='chevron left' />
</Menu.Item>
<Menu.Item as='a'>1</Menu.Item>
<Menu.Item as='a'>2</Menu.Item>
<Menu.Item as='a'>3</Menu.Item>
<Menu.Item as='a'>4</Menu.Item>
<Menu.Item as='a' icon>
<Icon name='chevron right' />
</Menu.Item>
</Menu>
</Table.HeaderCell>
</Table.Row>
</Table.Footer>
</Table>
)
}
export default PlayListTable
You may be receiving correct data but you don't update your state at the correct time. spotlist
returns a Promise that you are chaining from, but the setPlaylists(tablelist)
call is enqueued before the then
block of the promise chain is processed. The useEffect
callback is 100% synchronous code.
let spotlist = Spotify.playlistsearch(searchString);
let tablelist = [];
spotlist.then(val => { // <-- (1) then callback is placed in the event queue
val.forEach(element => { // <-- (3) callback is processed, tablelist updated
tablelist.push({
name: element.description,
track_count: element.tracks.total,
});
}
)});
setPlaylists(tablelist); // <-- (2) state update enqueued, tablelist = []
You can forEach
into a temp array, but mapping the response data to state values is the more "React" way of handling it. It is also more succinct.
Spotify.playlistsearch(searchString)
.then(val => {
setPlaylists(val.map(element => ({
name: element.description,
track_count: element.tracks.total,
})));
}
)});