0

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.

Jimil
  • 3
  • 1
  • 4
  • 1
    Hooks are for function style React components. You cannot use them in class components. `constructor`, `render` and other life cycle functions are gone in function style React components. See https://stackoverflow.com/questions/60961065/unable-to-use-usestate-in-class-component-react-js – Desmond Apr 09 '21 at 09:12

2 Answers2

1

React has two ways of using components :

Class components

Declared this way : class ComponentName extends Component {

then your state is managed using : this.setState()

Function components

Declared just as a function as your second example

There you can use hooks and the useState()

So if you're not planning to re-write all your component you'll have to use this.setState()

Seba99
  • 1,197
  • 14
  • 38
0

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>
kunal panchal
  • 798
  • 5
  • 21
  • 1
    it didn't work directly but did little bit tweaking here and there. And IT WORKED!!!! Thanks so much dude. You made my day. – Jimil Apr 09 '21 at 09:50