John Hess
John Hess

Reputation: 233

React js on submit function firing on page load

I am new to React. I am trying to put together a simple app with three components - a parent component (SearchContainer) and two children (SearchForm and ResultsContainer). The idea is for the input on the search form to update the state of SearchForm with the search query. Then there is an onSubmit function for the form that triggers an AJAX request that takes the query, hits an API, and retrieves the search results. Right now, the onSubmit function is firing as soon as the page loads and continues to fire over and over. I can't figure out why this is happening. Here is the code:

SearchContainer (parent component):

var React = require('react');
var ResultsContainer = require('./ResultsContainer.jsx')
var SearchForm = require('./SearchForm.jsx')

var SearchContainer = React.createClass({
  getInitialState: function () {
    return {
      results: null,
      formAction: 'http://localhost:3000/search',
      formMethod: 'get',
    };
  },
  executeSearch: function(query) {
    console.log("executing search");
    var data = {
      query: query,
    };
    $.ajax({
      url: this.state.formAction,
      data: data,
      dataType: 'json',
      success: this.successFunction,
      error: this.errorFunction,
    });
  },

  handleSearch: function(query) {
    this.executeSearch(query);
  },
  successFunction: function(response){
    console.log("success");
    this.setState({results: response["results"]});
  },
  errorFunction: function(){
    console.log("error");
  },
  render: function () {
    return (
     <div className='center-text'>
       <SearchForm formAction={this.state.formAction} formMethod={this.state.formMethod} handleSearch={this.handleSearch}/>  
       <ResultsContainer results={this.state.results}/>
     </div>
    );
  },
});

module.exports = SearchContainer; 

SearchForm (child):

var React = require('react');
var ResultsContainer = require('./ResultsContainer.jsx')


var SearchForm = React.createClass ({
  getInitialState: function () {
    return {
      query: "",
    };
  },

  handleChange: function(event) {
    this.setState({query: event.target.value});
  },

  render: function () {
    return (
      <div>
        <form onSubmit={this.props.handleSearch(this.state.query)} >
          <input className="query" type="text" placeholder="Search..." onChange={this.handleChange}></input>
          <input type="submit" value="Search" ></input>
        </form>
      </div>
    );
  },

});

module.exports = SearchForm;

What is causing the handleSearch function to fire over and over again? Thanks for your help.

Upvotes: 5

Views: 16705

Answers (4)

spetsnaz
spetsnaz

Reputation: 1291

Anything you placed inside curly braces { ... } in React will be considered as a JavaScript expression and of course run when the render() method runs.

INSTEAD

<form onSubmit={console.log('sorry, I am fired on page load! ') }></form>

DO LIKE THIS

logToConsole() {

     console.log('I will be logged once form is submitted :)');
}

render(
   return (<form onSubmit={this.logToConsole}></form>)
)

### 1st SOLUTION:
Surely what you need to pass to an event handler is a function that is going to be triggered on event fire.

    handleSubmit(e) {
         e.preventDefault(); // prevent native submitting behavior

         // do anything on submit, here!

    }
    render() {
        return(
            <form onSubmit={this.handleSubmit}>
                 ......
            </form>
        )
    }

### 2nd SOLUTION:
You can define a custom event handler as stated above, or you may also use Arrow functions to get the job done inline.
See for more about Arrow functions: http://exploringjs.com/es6/ch_arrow-functions.html

    render() {
        return(
            <form onSubmit={(e) => {e.preventDefault(); /* DO SOMETHING HERE */}}>
                 ......
            </form>
        )
    }

Upvotes: 7

Bhargav Ponnapalli
Bhargav Ponnapalli

Reputation: 9412

Try this.

Replace

  {this.props.handleSearch(this.state.query)}

With

{this.props.handleSearch.bind(null,this.state.query)}

So the form will now be

  <form onSubmit={this.props.handleSearch.bind(null,this.state.query)} >
      <input className="query" type="text" placeholder="Search..." onChange={this.handleChange}></input>
      <input type="submit" value="Search" ></input>
    </form>

Reason:

In your code, you are actually invoking the onSubmit function without the submit event being triggered. In the new code, you are just binding a function to an event. It will be invoked when the event actually fires.

Edit:

If you need the event object as well, to prevent default.

handleSearch: function(query,event) {
    console.log(event);
    event.preventDefault();
    this.executeSearch(query);
}

Upvotes: 4

Henrik Andersson
Henrik Andersson

Reputation: 47172

This line calls the function when rendering the form.

<form onSubmit={this.props.handleSearch(this.state.query)}>

to work around it don't put the () and instead access this.state.query from within your submit handler. React will execute any function that it finds on each render pass.

handleSearch (event) {
    event.preventDefault();
    this.props.handleSearch(this.state.query);
}

and your form would then look like this

<form onSubmit={this.handleSearch}>

Upvotes: 0

Andy Ray
Andy Ray

Reputation: 32066

It's because you're calling the search function:

this.props.handleSearch(this.state.query)

The render method runs when the page loads and will call any functions you tell it to.

You may want to do something like

handleSearch( event ) {
    event.preventDefault();
    this.props.handleSearch(this.state.query);
},

render() {
    ...
    onSubmit={this.handleSearch}

Upvotes: 0

Related Questions