Reputation: 2240
Im running React and Rails 5.2 with webpacker.
I have an ElasticSearch Search bar at the top of the page, and I am having trouble sending the proper request to the back end, and allowing the rails back end to process the search request.
We are no where near ready to have this as a SPA right now, but I cant seem to get the params to be populated.
import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import {asyncContainer, Typeahead} from 'react-bootstrap-typeahead';
const AsyncTypeahead = asyncContainer(Typeahead);
class SearchBar extends Component {
constructor(props) {
super(props)
this.state = {
options: ['Please Type Your Query'],
searchPath: '/error_code/search',
selected: [""],
}
this.handleSubmit = this.handleSubmit.bind(this);
this.handleChange = this.handleChange.bind(this);
}
searchErrorCodes(term) {
fetch(`/error_code/auto?query=${term}`)
.then(resp => resp.json())
.then(json => this.setState({options: json}))
}
handleChange(error_code_name) {
let newValue = error_code_name
this.setState({
selected: newValue
});
this.setState({
searchPath: `/error_code/search?error_code=${this.state.selected}`,
});
console.log(`This is the new searchPath is ${this.state.searchPath}`);
}
handleSubmit(e) {
alert(`submitted: ${this.state.selected}`);
// event.preventDefault();
}
render() {
return (
<div>
<form ref="form"
action={this.state.searchPath}
acceptCharset="UTF-8"
method="get"
onSubmit={e => this.handleSubmit(e)}
>
<AsyncTypeahead
onSearch={term => this.searchErrorCodes(term)}
options={this.state.options}
className="search"
onClick={e => this.handleSubmit(e)}
selected={this.state.selected}
onChange={e => this.handleChange(e)}
/>
<button
action={this.state.searchPath}
acceptCharset="UTF-8"
method="get"
type="submit"
className="btn btn-sm btn-search">
<i className="fa fa-search"></i>
</button>
</form>
</div>
)
}
}
ReactDOM.render(<SearchBar/>, document.querySelector('.search-bar'));
Everything is rendering correctly, but the input is not being sent properly to the controller.
Upvotes: 0
Views: 1041
Reputation: 5645
setState
is asynchronous in nature and multiple setState
calls in short order can results in a batch update. Meaning the last update wins. Your second setState call is overriding the first one.
Think of setState() as a request rather than an immediate command to update the component. For better perceived performance, React may delay it, and then update several components in a single pass. React does not guarantee that the state changes are applied immediately.
Considering you aren't doing any calculation from the previous state or props... You should change your setState call to the following:
this.setState({
selected: newValue,
searchPath: `/error_code/search?error_code=${newValue}`
});
You can also use a function as the updater
for setState(updater, [callback])
if you need the pervious state or props to calculate the new state.
this.setState((prevState, props) => {
return {counter: prevState.counter + props.step};
});
Both prevState and props received by the updater function are guaranteed to be up-to-date. The output of the updater is shallowly merged with prevState.
As an aside: Please have a look at Why JSX props should not use arrow functions. It's rather detrimental to use them inline.
Upvotes: 1