I have a search input I'd like to clear after the value is submitted and the search is performed with the value. In similar questions, it was suggested to set the state of the input value to '', but I think that's what I tried and it didn't do anything.

I only have a parent and child component in my app. The parent component has a method for searching jokes (searchJokes), and it is passed down as a prop with a different name to the child component in the component instance with onFormSubmit={this.searchJokes}. In the child component, when the user enters something into the search input, its event.target.value is passed with onChange={e => props.onInputChange(e.target.value)} corresponding to the onSearchChange method in the parent prop, and the value is used to update the state of searchTerm.

I added searchTerm: '' to the end of the searchJokes method, which fetches a search according to the search term, as you can see in the parent component code below.

Parent component:

class App extends Component {
  constructor() {
    super();

    this.state = {
      searchTerm: '',
      jokes: [],
      isFetchingJokes: false,
      isSearch: false
    };

    this.onSearchChange = this.onSearchChange.bind(this);
    this.randomizeJokes = this.randomizeJokes.bind(this);
    this.searchJokes = this.searchJokes.bind(this);
  }

  randomizeJokes() {
    this.setState({
      isFetchingJokes: true,
      isSearch: false
    });

    fetch(
      'https://icanhazdadjoke.com/',
      {
        method: 'GET',
        headers: {
          Accept: 'application/json'
        }
    })
      .then(response => response.json())
      .then(json => {
        let joke = json.joke;
        this.setState({
          joke,
          isFetchingJokes: false
        });
      });
  }

  searchJokes(limit = 15) {
    // If nothing entered, user gets "Please fill out this field" message due to "required" attribute on input element
    if (this.state.searchTerm !== '') {
      this.setState({
        isFetchingJokes: true,
        isSearch: true
      });

      fetch(
        `https://icanhazdadjoke.com/search?term=${
          this.state.searchTerm
        }&limit=${limit}`,
        {
          method: 'GET',
          headers: {
            Accept: 'application/json'
          }
      })
        .then(response => response.json())
        .then(json => {
          let jokes = json.results;
          this.setState({
            jokes,
            isFetchingJokes: false,
            searchTerm: '' // <-- DOESN'T CLEAR INPUT
          });
        });
    }
  }

  onSearchChange(value) {
    this.setState({ searchTerm: value });
  }

  jokeRender() {
    return (
      <div>
        {this.state.isSearch ?
          <ul>{this.state.jokes.map(item => <li key={item.id}>{item.joke}</li>)}
          </ul> : <p className="random-joke">{this.state.joke}</p>}
      </div>
    );
  }

  render() {
    return (
      <div>
        <h1>Dad Jokes</h1>
        <RetrievalForm
          onFormSubmit={this.searchJokes}
          onInputChange={this.onSearchChange}
          isSearching={this.state.isFetchingJokes}
          onRandomize={this.randomizeJokes}
        />

        {this.state.isFetchingJokes ? <p className="searching-message">Searching for jokes...</p> : this.jokeRender()}
      </div>
    );
  };
}

Child component:

const RetrievalForm = props => {
  const onSubmit = e => {
    // Prevents GET request/page refresh on submit
    e.preventDefault();
    props.onFormSubmit();
  };

  return (
    <>
      <form onSubmit={onSubmit}>
        <input
          type="text"
          placeholder="Enter search term..."
          onChange={e => props.onInputChange(e.target.value)}
          required
        />
        <div>
          {/* Specifying type here since it's good practice; different browsers may use default types for buttons */}
          <button type="submit" disabled={props.isSearching}>Search</button>
          {/* type="button" stops input validation message from being displayed (on Firefox) when randomize button is clicked without anything entered */}
          <button type="button" onClick={props.onRandomize} disabled={props.isSearching} className="randomize-button">
            Randomize
          </button>
        </div>
      </form>
    </>
  );
};

Any help would be greatly appreciated.

2 Answers

1
Snukus On Best Solutions

You need to pass your searchTerm down to the RetrievalForm and in that input set value={searchTerm} so that it's value will be bound to that state.

1
AryanJ-NYC On

Basically, you need to store the input value in the component's state. When onSubmit is called, we should revert that value to an empty string.

Example with some React Hooks goodness:

import React, { Component, useState } from 'react';

const RetrievalForm = props => {
  const [searchTerm, setSearchTerm] = useState('');

  const onChange = e => {
    const { value } = e.target;
    props.onInputChange(value);
    setSearchTerm(value)
  }

  const onSubmit = e => {
    // Prevents GET request/page refresh on submit
    e.preventDefault();
    props.onFormSubmit();
    setSearchTerm('');
  };

  return (
    <>
      <form onSubmit={onSubmit}>
        <input
          type="text"
          value={searchTerm}
          placeholder="Enter search term..."
          onChange={onChange}
          required
        />
        <div>
          {/* Specifying type here since it's good practice; different browsers may use default types for buttons */}
          <button type="submit" disabled={props.isSearching}>
            Search
          </button>
          {/* type="button" stops input validation message from being displayed (on Firefox) when randomize button is clicked without anything entered */}
          <button type="button" onClick={props.onRandomize} disabled={props.isSearching} className="randomize-button">
            Randomize
          </button>
        </div>
      </form>
    </>
  );
};

Example here: https://stackblitz.com/edit/react-db5ire