Home > Blockchain >  Why can't I map over an array of object in React.js after passing data to another component?
Why can't I map over an array of object in React.js after passing data to another component?

Time:12-16

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

  • Related