简体   繁体   English

React.js 从头开始​​自动完成

[英]React.js Autocomplete from scratch

As part of a technical test, I've been asked to write an autocomplete input in React.作为技术测试的一部分,我被要求在 React 中编写一个自动完成输入。 I've done this but I'd now like to add the functionality of navigating up and down the rendered list with the arrow keys.我已经这样做了,但我现在想添加使用箭头键在渲染列表中上下导航的功能。 I've done some extensive Googling and found nothing React specific apart from npm packages.我已经做了一些广泛的谷歌搜索,发现除了 npm 包之外没有任何特定于 React 的东西。

To be clear, I'm looking for something like this but for React: https://www.w3schools.com/howto/howto_js_autocomplete.asp明确地说,我正在寻找这样的东西,但对于 React: https : //www.w3schools.com/howto/howto_js_autocomplete.asp

All I basically need is the arrow button functionality, I've got everything else working fine.我基本上只需要箭头按钮功能,其他一切正常。

Cheers干杯

Here's an example that I tried but couldn't get working.这是我尝试过但无法正常工作的示例。

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

And here is my code:这是我的代码:

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

Code that renders the list from the restful API:从 restful API 呈现列表的代码:

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

Since you are defining a function as handleKeyDown(e) {...} the context this is not pointing to the context of class instance, the context will be supplied by onKeyDown (and I suppose it's window as this )由于您将函数定义为handleKeyDown(e) {...}上下文this不指向类实例的上下文,因此上下文将由 onKeyDown 提供(我认为它是window作为this

So, you have 2 ways to go:所以,你有两种方法:

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

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

Also, don't forget that you may want a mod items.length counter, meaning when your press down and the last item is already selected, it would go to the first item.另外,不要忘记您可能需要一个 mod items.length 计数器,这意味着当您按下并选择最后一个项目时,它会转到第一个项目。

Your api usage with storing markdown into the state is just a terrible thing to do.您将降价存储到状态中的 api 用法只是一件可怕的事情。 You don't have access to these strings anymore, instead save it as a plain array.您无法再访问这些字符串,而是将其保存为普通数组。 Pass it where you need it, and use it to create jsx there.将它传递到您需要的地方,并使用它在那里创建 jsx。

Also, you don't use cursor from your state at all.此外,您根本不使用您所在州的光标。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM