从头开始React.js自动完成

时间:2018-11-09 11:07:37

标签: javascript reactjs autocomplete

作为技术测试的一部分,有人要求我在React中编写一个自动完成输入。我已经做到了,但是现在我想添加使用箭头键在渲染列表中上下导航的功能。我已经做了一些广泛的Google搜索,除了npm软件包之外,什么都没有发现React专用。

需要明确的是,我正在寻找类似React的东西:https://www.w3schools.com/howto/howto_js_autocomplete.asp

我基本上只需要箭头按钮功能,其他所有功能都可以正常工作。

欢呼

这是我尝试过但无法正常工作的示例。

export default class Example extends Component {
  constructor(props) {
    super(props)
    this.handleKeyDown = this.handleKeyDown.bind(this)
    this.state = {
      cursor: 0,
      result: []
    }
  }

handleKeyDown(e) {
    const { cursor, result } = this.state
    // arrow up/down button should select next/previous list element
    if (e.keyCode === 38 && cursor > 0) {
      this.setState( prevState => ({
        cursor: prevState.cursor - 1
      }))
    } else if (e.keyCode === 40 && cursor < result.length - 1) {
      this.setState( prevState => ({
        cursor: prevState.cursor + 1
      }))
    }
  }

  render() {
    const { cursor } = this.state

    return (
      <Container>
        <Input onKeyDown={ this.handleKeyDown }/>
        <List>
          {
            result.map((item, i) => (
              <List.Item
                key={ item._id }
                className={cursor === i ? 'active' : null}
              >
                <span>{ item.title }</span>
              </List.Item>
            ))
          }
        </List>
      </Container>
    )
  }
}

这是我的代码:

class Search extends Component {
  constructor(props) {
    super(props);
    this.state = {
      location: '',
      searchName: '',
      showSearch: false,
      cursor: 0
    };
  }

handleKeyPress = e => {
    const { cursor, searchName } = this.state;
    // arrow up/down button should select next/previous list element
    if (e.keyCode === 38 && cursor > 0) {
      this.setState(prevState => ({
        cursor: prevState.cursor - 1
      }));
    } else if (e.keyCode === 40 && cursor < searchName.length - 1) {
      this.setState(prevState => ({
        cursor: prevState.cursor + 1
      }));
    }
  };

 render() {
    const { searchName, location } = this.state;

    return (
      <div className="Search">
        <h1>Where are you going?</h1>
        <form id="search-form" onSubmit={this.handleSubmit}>
          <label htmlFor="location">Pick-up Location</label>
          <input
            type="text"
            id="location"
            value={location}
            placeholder="city, airport, station, region, district..."
            onChange={this.handleChange}
            onKeyUp={this.handleKeyUp}
            onKeyDown={this.handleKeyPress}
          />

          {this.state.showSearch ? (
            <Suggestions searchName={searchName} />
          ) : null}

          <button value="submit" type="submit" id="search-button">
            Search
          </button>
        </form>
      </div>
    );
  }

从静态API呈现列表的代码:

.then(res =>
  this.setState({
    searchName: res.data.results.docs.map(array => (
      <a href="#">
        <div
          key={array.ufi}
          className="locations"
        >
          {array.name}
        </div>
      </a>
    ))
  })
);

1 个答案:

答案 0 :(得分:0)

由于您将函数定义为handleKeyDown(e) {...},因此上下文this并不指向类实例的上下文,因此该上下文将由onKeyDown提供(我假设它是window this

因此,您有2种方法:

  1. 将您的函数声明为handleKeyDown = (e) => {...}

  2. 将handleKeyDown上下文绑定到组件实例,例如onKeyDown={this.handleKeyDown.bind(this)}

此外,别忘了您可能需要一个mod items.length计数器,这意味着当您按下并选择了最后一个项目时,它将转到第一个项目。

您的api用法(将markdown存储到状态中)只是一件可怕的事情。您再也无法访问这些字符串,而是将其另存为纯数组。将其传递到您需要的位置,然后用它在此处创建jsx。

此外,您根本不会使用状态中的光标。