27
27

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

react.jsでautocompleteをやってみる

Last updated at Posted at 2015-09-07

モチベーション

autocompleteをするときに、jQueryのライリブラリは豊富にあります。react.jsでautocompleteを行うライブラリは幾つか存在して、jQueryのライブラリを使っているものもあります。けれども、できればjQueryを使わずにreact.jsだけでautocompleteを使いたいです。

ezequiel/react-typeahead-component

react.jsだけでautocompleteを実現しているライブラリは幾つかありますが、今回はezequiel/react-typeahead-componentを使いました。

特徴として次のものがあります(プロジェクトページからの引用)。

  • Accessibility.
  • BiDi support for RTL languages.
  • Keyboard navigation.
  • Hinting support for the current input value.
  • Autocompletion of the hint when possible.
  • Custom templates for each option.
  • Auto-closing dropdown for the options list.
  • 5KB minified+gzipped!

必要十分そうな気がします。他のライブラリを十分調べたわけではないのですが、他のライブラリも同等だと思います。

サンプル

プロジェクトの中にfluxを使ったサンプルコードもあり、わかりやすいです。

コード例

今回はfluxを使わずに、autocompleteを使って実装してみます。作るものは、ユーザの名前をサジェストしてくれるシステムです。コードはES6の記法で書きます。

import React from 'react';
import Typeahead from 'react-typeahead-component';
import request from 'superagent';
import {throttle} from 'lodash';
import MyOptionTemplate from './my-option-template.jsx';

export default class UserSearch extends React.Component {
  constructor() {
    super();
    this.state = {
      initValue: '',
      options: []
    }
    this.getOptions = throttle(this.getOptionsFromApi, 300);
  }

  render() {
    return (
      <Typeahead
        placeholder="ユーザ検索"
        inputValue={this.state.inputValue}
        options={this.state.options}
        onChange={this.handleChange.bind(this)}
        optionTemplate={MyOptionTemplate}
        onOptionChange={this.handleOptionChange.bind(this)}
      />
    );
  }

  handleChange(evt) {
    let value = evt.target.value;
    this.setState({inputValue: value});
    this.getOptions(value);
  }

  getOptionsFromApi(value) {
    reqeust.get("/api/suggest")
      .query({q: value})
      .end(
        (err, res) => {
          let list = JSON.parse(res.text);
          this.setState({options: list});
        }
      )
  }

  handleOptionChange(evt, option) {
    this.setState({inputValue: option});
  }

  handleOptionClick(evt, option) {
    this.setState({inputValue: option});
  }

}

stateで管理するのは、inputタグの値を保持するinputValueとautocompleteで補完する候補を保持するoptionsの二つです。optionsは文字列の配列です。

throttleでオプションを取得するのは300msecごとに設定しています。一文字入力するごとに即座に候補を取得すると、サーバに負荷がかかりすぎる為の処置です。

Typeaheadでは多くのpropsを取りますが、最低限必要そうなのが、inputValue, options, onChange, optionTemplate, onOptionChangedです。inputValueは入力エリアの値、optionsは候補リストです。onChangeは入力エリアの値が変更した時に呼び出されます。値が変更したら、getOptionFromApiでサーバに候補一覧をajaxで取得します。取得したものは、stateに保持します。
onOptionChangeとonOptionClickは候補リストから選択した時に呼びだされます。通常はstateのinputValueをセットするだけです。

さて、optionTemplateですが、候補リストの表示形式を変更します。デフォルトのままだとあまりにも悲しいので、変更するのが良いでしょう。でも、今回はめんどくさいのでspanタグで囲むだけです。
ユーザ検索なので、検索候補にアバターのような写真のようなものも表示するものいいいですね。

import React from 'react';


export default class MyOptionTemplate extends React.Component {
  render() {
    return (
      <div className="userSearchOptions">
        {this.renderOptions()}
      </div>
    );
  }

  renderOptions() {
    let optionData = this.props.data;
    let inputValue = this.props.userInputValue;
    if (optionData) {
      return (
        <span>
          {optionData}
        </span>
      )
    }
  }
}

ついでに、CSSも




.react-typeahead-input-container {
    border: 1px solid #ccc;
    box-shadow: inset 0 1px 2px #eee;
}

.react-typeahead-input-container input {
    font-size: 16px;
    height: 27px;
    padding: 2px 6px;
    width: calc(100% - 12px);
    border: 0;
    outline: none;
}

.react-typeahead-input-container input:focus {
    border: 1px solid #1c62b9;
    box-shadow: inset 0 1px 2px rgba(0,0,0,0.3);
}

.react-typeahead-options {
    margin: 0;
    padding: 0;
    list-style-type: none;
    border: 1px solid #ccc;
    border-top: 0;
    cursor: default;
    box-shadow: 0 2px 4px rgba(0,0,0,0.2);
    z-index: 200;
}

.react-typeahead-options li {
  padding: 5px;
}

クラス名から多分、それぞれ何をしているか想像がつくと思います。

27
27
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
27
27

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?