tl;dr: this.setState({ results: body.hits.hits });
doesn't work
I need to render the response from an ElasticSearch index in React.js v16. I do have working code for React v < 15.5:
That I broke after re-writing it with ES6 class syntax:
class App extends Component {
constructor(props) {
super(props)
this.state = { results: [] };
}
handleChange(event) {
const search_query = event.target.value;
client.search({
index: _index,
type: _type,
body: {
query: {
multi_match: {
query: search_query,
fields: ['title^100', 'tags^100', 'abstract^20', 'description^10', 'chapter^5', 'title2^10', 'description2^10'],
fuzziness: 1,
},
},
},
}).then(function(body) {
this.setState({ results: body.hits.hits });
}.bind(this),
function(error) {
console.trace(error.message);
}
);
}
render() {
return (
<div className="container">
<input type="text" onChange={this.handleChange} />
<SearchResults results={this.state.results} />
</div>
);
}
}
I am using an App component to set initialState results to empty array inside a constructor. Then use a handleChange function to take text inputs from the input field and send them as search queries to ES. This works, I can see the console trace for body.hits.hits, that looks something like this:
TRACE: 2017-10-19T09:35:37Z
-> POST http://localhost:9200/myIndex_2017_09_09/article/_search
{
"query": {
"multi_match": {
"query": "query",
"fields": [
"title^100",
"tags^100",
"abstract^20",
"description^10",
"chapter^5",
"title2^10",
"description2^10"
],
"fuzziness": 1
}
}
}
<- 200
{
"took": 19,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 369,
"max_score": 18.169382,
"hits": [
{
"_index": "myIndex_2017_09_09",
"_type": "article",
"_id": "AV5mDaz7Jw6qOfpXAp1g",
"_score": 18.169382,
"_source": {
"title2": "title2",
"series": [
"series1",
"series2",
"series3"
],
"models": [
"models1",
"models2"
],
"description": "description",
"description2": "description2",
"link": "URL",
"title": "title",
"chapter": "chapter",
"tags": [
"tags1",
"tags2",
"tags3"
],
"image": "URL",
"abstract": "abstract"
}
}
]
}
}
I then add a render function to display the input field and another stateless component SearchResults to iterate some JSX over the response. This component is passed down this.state.results, which does not seem to work:
const SearchResults = ({results}) => (
<div className="search_results">
<hr />
<table>
<thead>
<tr>
<th>Title</th>
</tr>
</thead>
<tbody>
{results.map((result , i) =>
<ResultRow key={i}
title={result._source.title2} />
)}
</tbody>
</table>
</div>
)
const ResultRow = ({ title }) => (
<tr>
<td>
{title}
</td>
</tr>
)
The state of SearchResults always shows up as an empty array. But when I add some dummy data to App constructor, this renders just fine:
constructor(props) {
super(props)
this.state = { results: [
{
"_index": "myIndex_2017_09_09",
"_type": "article",
"_id": "AV5mDXcSJw6qOfpXAp0a",
"_score": 5.5604653,
"_source": {
"title2": "title 01",
}
},
{
"_index": "myIndex_2017_09_09",
"_type": "article",
"_id": "AV5mDXcSJw6qOfpXApsa",
"_score": 2.1404631,
"_source": {
"title2": "title 02",
}
}
]}
}
Can someone spot the error?