Search code examples
reactjsreact-hooksthemoviedb-api

I want to use react hook 'useState' to save the information fetched from API and show on the scrren. But, I can't use in class so what can I do?


So, for some context I'm fetching some search results on click on search button. The result shows in console.log() after clicking search button perfectly. the SearchComponent.js is below.

import React, { Component, useState } from 'react'
import { API_KEY, API_URL } from '../config/keys';
import { Link } from 'react-router-dom';

class SearchBox extends Component {

constructor(props) {
    super(props);

    this.state = {
      searchQuery: ""
    }

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
    this.onChangeValue = this.onChangeValue.bind(this);
  }

handleChange = (e) => {
    e.preventDefault();
    const { name, value } = e.target;
    this.setState({ [name]: value });
}

handleSubmit = (e) => {

    e.preventDefault();
    var data = this.state.searchQuery;
    const url = `${API_URL}search/${this.state.selectedOption}?api_key=${API_KEY}&language=en-US&query=${encodeURI(data)}&page=1&include_adult=false`;

    fetch(url)
    .then(response => response.json())
    .then(response => {
        console.log(response);
        const result = response.results; 
    })
}

onChangeValue(event) {
    this.setState({
        selectedOption: event.target.value
      });
}

render() {
return (
    <>
    <div className="mt-3">
    {/* Breadcrumb */}
        <div style={{ width: '95%', margin: '1rem auto' }}>
            <nav aria-label="breadcrumb">
                <ol className="breadcrumb">
                    <li className="breadcrumb-item"><Link to='/'>Home</Link></li>
                    <li className="breadcrumb-item active" aria-current="page">Search</li>
                </ol>
            </nav>
        </div>

        <div className="row">
            <div className="col-6 offset-3">
                <form className="form-group">
                    <div className="input-group">
                        <input 
                        className="form-control"
                        type="text"
                        placeholder= 'Search...'
                        onChange={this.handleChange}
                        name= 'searchQuery'
                        value={this.state.searchQuery} /> 
                        <button onClick={this.handleSubmit} type="submit" className="btn btn-primary input-group-addon" ><span className="fa fa-search fa-lg"></span></button>
                    </div>
                    {/* radio buttons */}
                    <div className="mt-2">
                        <div class="form-check">
                            <input 
                            class="form-check-input" 
                            type="radio" 
                            name="movie" 
                            value="movie"
                            checked={this.state.selectedOption === "movie"}
                            onChange={this.onChangeValue}
                            />
                            <span class="form-check-label font-weight-bold">
                                Movies
                            </span>
                        </div>
                        <div class="form-check">
                            <input 
                            class="form-check-input" 
                            type="radio" 
                            value="tv" 
                            name="tvshow" 
                            checked={this.state.selectedOption === "tv"}
                            onChange={this.onChangeValue}
                            />
                            <span class="form-check-label font-weight-bold">
                                TV Shows
                            </span>
                        </div>
                    </div>
                </form>
            </div>
        </div>
    </div>

    {/* search results */}
    <div style={{ width: '95%', margin: '1rem auto' }}>
        <div className="text-center">
            <div className="font-weight-lighter h2"> Search Results </div>

        </div>
    </div>
    </>
)
}
}

export default SearchBox;

the array of result is in result variable of handleSubmit(). how can I use useState to store my result var and then show it on scrren.

if you don't understand how i'm talking about using this hook i've attached a file which does similar thing. landingComponent.js

import React, { useEffect, useState } from 'react';
import {API_URL, API_KEY, IMAGE_URL} from '../../config/keys';
import { Row } from 'reactstrap';
import MainImage from './MainImage';
import GridCard from './GridCard';
import { Link } from 'react-router-dom';


function LandingPage() {

const [Movies, setMovies] = useState([]);
const [CurrentPage, setCurrentPage] = useState(0);

useEffect( () => {
    const endpoint = `${API_URL}movie/popular?api_key=${API_KEY}&language=en-US&page=1`;
    fetchMovies(endpoint);
}, []);

const fetchMovies = (path) => {
    fetch(path)
    .then(response => response.json())
    .then(response => {
        console.log(response);
        setMovies([...Movies, ...response.results]);
        setCurrentPage(response.page);
    })
}

const handleClick = () => {
    const endpoint = `${API_URL}movie/popular?api_key=${API_KEY}&language=en-US&page=${CurrentPage + 1}`
    fetchMovies(endpoint);
}

return (
    <div style={{ width: '100%', margin: 0 }}  >

        

        <div style={{ width: '95%', margin: '1rem auto' }}>
            {/* Breadcrumbs */}
            <nav aria-label="breadcrumb">
                <ol className="breadcrumb">
                    <li className="breadcrumb-item"><Link to='/'>Home</Link></li>
                    <li className="breadcrumb-item active" aria-current="page">Movies</li>
                </ol>
            </nav>
            <div className="font-weight-bold h2"> Latest Movies </div>
            <hr style={{borderColor:'black'}}/>

            <Row>
                    {Movies && Movies.map((movie, index) => (
                        <React.Fragment key={index}>
                            <GridCard 
                                image={movie.poster_path && `${IMAGE_URL}w500${movie.poster_path}`}
                                movieId={movie.id} movieTitle={movie.title} name={movie.original_title}
                            />
                        </React.Fragment>
                    ))}
            </Row>

            <br />
            <div className="text-center">
                <button className="btn btn-primary" onClick={handleClick}> Load More </button>
            </div>

        </div>

    </div>
)
}

export default LandingPage

I want to use same way in SearchComponent.js. I tried so many thing but none worked. Help is appreciated.


Solution

  • When you fetch the data you need to store it in the state again creating results:[] property in the state.

    handleSubmit = (e) => { 
        e.preventDefault();
        var data = this.state.searchQuery;
        const url = `${API_URL}search/${this.state.selectedOption}?api_key=${API_KEY}&language=en-US&query=${encodeURI(data)}&page=1&include_adult=false`;
    
        fetch(url)
        .then(response => response.json())
        .then(response => {
            console.log(response);
            const result = response.results; 
            this.setState({results:result}); //Here you store the state.
        });
    }
    

    Now you will have to show it in the results JSX block.

    {/* search results */}
    <div style={{ width: '95%', margin: '1rem auto' }}>
      <div className="text-center">
        <div className="font-weight-lighter h2"> Search Results </div>
        <div className="results">
          <ul>
            {this.state.results.length && this.state.results.map(item => { return (
            <li> {item} </li>
            ) })}
          </ul>
    
        </div>
      </div>
    </div>