Search code examples
javascriptreactjsaxiosbing-api

How do I update my Bing web API search results in React.js after submitting query in search bar (serp format)


I am using the Bing Web Search API, and I am accessing the data when typing a query into the search bar I created. But I have not been able to get the data to display in my search results when submitting the search bar query. I am trying to access the elements in 'value' which is inside of 'webPages' as shown in the picture below: [search engine data]: https://i.sstatic.net/CRBjB.png

Bing Web Search: https://learn.microsoft.com/en-us/bing/search-apis/bing-web-search/reference/endpoints

If anyone could help with a detailed response it would be greatly appreciated!

useSearch.js:

import { useState, useEffect } from 'react';
import axios from 'axios';

const BASE_URL = 'https://api.bing.microsoft.com/v7.0/search';
const API_KEY = '0760f20a58f340a4ba3ce10857c43142'

const useSearch = ( {searchTerm} ) => {
    const [data, setData] = useState('');


    useEffect(() => {
        const fetchData = async () => {
            if (!searchTerm) return;
            try {
                const response = await axios.get(`${BASE_URL}`, {
                    headers: {
                        'Ocp-Apim-Subscription-Key': API_KEY,
                    },
                    params: {
                        'q': `${searchTerm}`,
                        'count': 10,
                        'mkt': 'en-us',
                    },
                });
                setData(response.data.webPages.value);
                // shows data from search bar
                console.log(response.data);

            } catch (error) {
                console.error('Error fetching data:', error);
            }
        };
        fetchData();
    }, [searchTerm]);

    return data;

};

export default useSearch;

SearchResults.js:

import React, { useState, useEffect } from 'react';
import axios from 'axios';
import TileItems from './TileItems';
import useSearch from './UseSearch';

const SearchResults = () => {
    const [theme, setTheme] = useState('light');
    const { data } = useSearch({ searchTerm: searchData });

    return (
      <div className=''>
        <main className={`main-container ${theme}`}>
          <section className="eighty" id="item-tiles">
            <h1>Search Results</h1>
            {data ? (
                <ul>
                  {data.map((i) => (
                      <TileItems
                          key={i.id}
                          image={i.thumbnailUrl}
                          title={i.name}
                          description={i.snippet}
                          website={i.url}
                      />
                  ))}
                </ul>
                ) : (
                  <p>Loading...</p>
                )}
          </section>
          <section id="item-tiles-right" className="twenty">
            <h2 id='col-2-header'>News</h2>
               {video ? (
                  <ul>
                    {/* this section is still under development */}
                    {video.map((v) => (
                        <iframe
                          id='ytplayer'
                          src={v.contentUrl}
                          frameborder='0'
                          allow='autoplay; encrypted-media'
                          width='100%'
                          height='360'
                          title='video'
                        />
                     ))}
                  </ul>
                  ) : (
                    <p>Loading...</p>
                  )}
          </section>
        </main>
      </div>
  );
};

Nav.js:

import React, { useState } from 'react';
import './NavBar.css';
import logo_light from '../../assets/spigot-logo.png';
import logo_dark from '../../assets/logo_light2.png';
import search_icon_light from '../../assets/search-w.png';
import search_icon_dark from '../../assets/search-b.png';
import toggle_light from '../../assets/night.png';
import toggle_dark from '../../assets/day.png';
import useSearch from '../UseSearch';


function NavBar({theme, setTheme, setSearchTerm}) {
  const [searchQuery, setSearchQuery] = useState('');
  const { data } = useSearch({ searchTerm: searchQuery});
  // console.log(setSearchQuery);

  /* ternary clause to change theme between light and dark mode */
  const toggle_mode = () => {
    theme == 'light' ? setTheme('dark') : setTheme('light');
  }

  return (
    <div className='navbar' >
        <img src={theme == 'light' ? logo_light : logo_dark} alt='' className='logo' />
        <ul className='nav-list'>
          <li>SEARCH</li>
        </ul>
      <div className='search-box'>
        <form>
           <input  className='search-bar' type='text' placeholder='Search' onChange={(e) => 
            setSearchQuery(e.target.value)}></input>
        </form>
        <img className='search-icon' src={theme == 'light' ? search_icon_light : 
           search_icon_dark} alt='' />
      </div>
        <img onClick={() => {toggle_mode()}} src={theme == 'light' ? toggle_light : 
           toggle_dark} alt='' className='toggle-icon'></img>
    </div>
  )
}

export default NavBar

Solution

  • The data returned from useSearch needs to be an array in order for you to map it, so in your useSearch hook you need to only get the value array if you want to only render the results.

    // in useSearch hook
    // we only take the array of webpages value
    // looking from your console.log screenshot
      setData(response.data.webPages.value);
    

    You are trying to map your searchData which is a string. In order for you to map the actual api data you would need to use the data returned from your useSearch hook

       // this is the API data
          // no need to destruct
        const data = useSearch({ searchTerm: searchData });
    
        // replace searchData with data
       {data ? (
                    <ul>
                      {data.map((i) => (
                          <TileItems
                              key={i.id}
                              image={i.thumbnailUrl}
                              title={i.name}
                              description={i.snippet}
                              website={i.url}
                          />
                      ))}
                    </ul>
                    ) : (
                      <p>Loading...</p>
                    )}
    

    Lemme know if this fixes your problem