React 16 визуализирует ответ ElasticSearch 5.x

вкратце: this.setState({ results: body.hits.hits }); не работает

Мне нужно отобразить ответ из индекса ElasticSearch в React.js v16. У меня есть рабочий код для React v ‹ 15.5:

Github

Это я сломал после переписывания с синтаксисом класса ES6:

Github

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>
      );
    }
}

Я использую компонент App для установки initialState results в пустой массив внутри конструктора. Затем используйте функцию handleChange, чтобы брать текстовые данные из поля ввода и отправлять их в качестве поисковых запросов в ES. Это работает, я вижу трассировку консоли для body.hits.hits, которая выглядит примерно так:

    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"
          }
        }
      ]
    }
  }

Затем я добавляю функцию рендеринга для отображения поля ввода и еще один компонент без сохранения состояния SearchResults для итерации некоторого JSX по ответу. Этот компонент передается this.state.results, который не работает:

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>
)

Состояние SearchResults всегда отображается как пустой массив. Но когда я добавляю некоторые фиктивные данные в конструктор App, это прекрасно отображается:

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",
              }
            }
      ]}
    }

Может ли кто-нибудь заметить ошибку?


person mpolinowski    schedule 19.10.2017    source источник


Ответы (1)


я думаю, проблема в том, что вы не связали контекст handleChange

вы можете сделать это в одном из двух мест

// in the constructor. refer below for why this is better
constructor(props) {
  // ...your stuff here

  this.handleChange = this.handleChange.bind(this)
}


//or in the actual element
<input type="text" onChange={this.handleChange.bind(this)} />

вы можете посмотреть здесь ссылки на руководство по стилю, которое я следую

person Maru    schedule 19.10.2017
comment
Спасибо за ваше время @Maru! Вот оно. Теперь это, кажется, работает как шарм :) - person mpolinowski; 19.10.2017