当用户停止输入

时间:2017-02-14 03:01:44

标签: reactjs settimeout

我需要在用户停止输入时执行搜索。我知道我应该使用 setTimeout()。但是使用 Reactjs我无法找到它是如何工作的。有人可以告诉我如何在用户停止键入几秒钟时调用一个方法(将处理搜索)。我想不了。在哪里编写代码以检查用户是否已停止输入。

import React, {Component, PropTypes} from 'react';

export default class SearchBox extends Component {

    state={
      name:" ",
    }

    changeName = (event) => {
        this.setState({name: event.target.value}); 
    }

    sendToParent = () => {
        this.props.searching(this.state.name);
    }

    render() {
        return (
            <div>
                 <input type="text"  placeholder='Enter name you wish to Search.'  onChange={this.changeName} />

            </div>
        );
    }
}   

我想在用户停止输入时调用sendToParent方法。

15 个答案:

答案 0 :(得分:33)

您可以按照以下方式使用setTimeout代码,

state = {
    name: '',
    typing: false,
    typingTimeout: 0
}
changeName = (event) => {
    const self = this;

    if (self.state.typingTimeout) {
       clearTimeout(self.state.typingTimeout);
    }

    self.setState({
       name: event.target.value,
       typing: false,
       typingTimeout: setTimeout(function () {
           self.sendToParent(self.state.name);
         }, 5000)
    });
}

此外,您需要在构造函数中绑定changeName处理程序函数。

constructor(props) {
   super(props);
   this.changeName = this.changeName.bind(this);
}

答案 1 :(得分:12)

另一种与我合作的方式:

class Search extends Component {
  constructor(props){
    super(props);
    this.timeout =  0;
  }

  doSearch(evt){
    var searchText = evt.target.value; // this is the search text
    if(this.timeout) clearTimeout(this.timeout);
    this.timeout = setTimeout(() => {
      //search function
    }, 300);
  }

   render() {
    return (
      <div className="form-group has-feedback">
        <label className="control-label">Any text</label>
        <input ref="searchInput" type="text" onChange={evt => this.doSearch(evt)} />
      </div>
    );
  }
}

答案 2 :(得分:12)

使用useEffect挂钩执行

function Search() {
  const [searchTerm, setSearchTerm] = useState('')

  useEffect(() => {
    const delayDebounceFn = setTimeout(() => {
      console.log(searchTerm)
      // Send Axios request here
    }, 3000)

    return () => clearTimeout(delayDebounceFn)
  }, [searchTerm])

  return (
    <input
      autoFocus
      type='text'
      autoComplete='off'
      className='live-search-field'
      placeholder='Search here...'
      onChange={(e) => setSearchTerm(e.target.value)}
    />
  )
}

答案 3 :(得分:3)

你可以使用lodash的debounce或使用setTimeout进行模拟。

import React, {Component, PropTypes} from 'react';

export default class SearchBox extends Component {
    constructor(props){
       super(props);
       this.state={ name:" "}
       this.timeout =  null;

    }

    changeName = (event) => {
        clearTimeout(timeout);
         if(timeout){
           setTimeout((event)=> this.setState({name: event.target.value}), 200)
         }
    }

    sendToParent = () => {
        this.props.searching(this.state.name);
    }

    render() {
        return (
            <div>
                 <input type="text"  placeholder='Enter name you wish to Search.'  onChange={this.changeName} />

            </div>
        );
    }
}

答案 4 :(得分:2)

这个library(使用反跳)非常简单。

设置

yarn add use-debounce

npm i use-debounce --save

文档中的用法示例

import React, { useState } from 'react';
import { useDebounce } from 'use-debounce';

export default function Input() {
  const [text, setText] = useState('Hello');
  const [value] = useDebounce(text, 1000);

  return (
    <div>
      <input
        defaultValue={'Hello'}
        onChange={(e) => {
          setText(e.target.value);
        }}
      />
      <p>Actual value: {text}</p>
      <p>Debounce value: {value}</p>
    </div>
  );
}

此刻我喜欢的东西可能在 未来!:

  • 易于设置和使用
  • 样板代码少
  • 适度的评分(〜1K)和使用情况(npm-每周20万次下载)
  • 支持超时,MaxWait和其他功能

答案 5 :(得分:1)

我认为我们可以用更简单,更简洁的方式来做到这一点,而不会破坏调用整个组件生命周期的state参数,

constructor(props) {
    super(props);

    //Timer
    this.typingTimeout = null;

    //Event
    this.onFieldChange = this.onFieldChange.bind(this);

    //State
    this.state = { searchValue: '' }; 
}   


 /**
 * Called on the change of the textbox.
 * @param  {[Object]} event [Event object.]
 */
onFieldChange(event) {
    // Clears the previously set timer.
    clearTimeout(this.typingTimeout);

    // Reset the timer, to make the http call after 475MS (this.callSearch is a method which will call the search API. Don't forget to bind it in constructor.)
    this.typingTimeout = setTimeout(this.callSearch, 475);

    // Setting value of the search box to a state.
    this.setState({ [event.target.name]: event.target.value });
}


<div className="block-header">
     <input
           type="text"
           name="searchValue"
           value={this.state.searchValue}
           placeholder="User Name or Email"
           onChange={this.onFieldChange}
     />
</div>

答案 6 :(得分:1)

我使用了lodash的去抖功能

onChangeSearchInput = (evt)=> {
    this.debouncedSearch(evt.target.value);
};

debouncedSearch = debounce(function (query) {
    this.setState({query});
}, 1000);

在我的渲染方法中的某个地方,我有这个输入字段

<input
    type='text'
    onChange={this.onChangeSearchInput}
    className='uk-input'
    placeholder={'search by name or email...'}
   />

答案 7 :(得分:1)

如何定制钩子?

import {useEffect, useRef, useState} from "react";

export default function useSearchInputState(searchHandler) {
  
  // to prevent calling the handler on component mount
  const didMountRef = useRef(false);

  const [searchValue, setSearchValue] = useState(null);

  useEffect(() => {
    let delayDebounceFn;

    if (didMountRef.current) {
      delayDebounceFn = setTimeout(searchHandler, 600)
    } else {
      didMountRef.current = true;
    }

    return () => clearTimeout(delayDebounceFn);
  }, [searchValue]); // eslint-disable-line react-hooks/exhaustive-deps

  return [searchValue, setSearchValue];

}

用法:

function MyComponent(props) {

  const [searchValue, setSearchValue] = useSearchInputState(() => {
    resetData(searchValue ?? null, selectedFilterPos);
  });

  const onSearchChange = e => {
    setSearchValue(e?.target?.value ?? null);
  }

  return (
    <input className="Search"
           onChange={onSearchChange}
      />
  );
}

答案 8 :(得分:0)

Typeahead库问题https://twitter.github.io/typeahead.js/

由于这里的案例很简单,我可以使用快速而肮脏的解决方案:

onChange: (event) ->
  if @_timeoutTask?
    clearTimeout @_timeoutTask

  @_timeoutTask = setTimeout (=>
    @sendToParent event.target.value
    clearTimeout @_timeoutTask
  ), 5000

这样,任务将在输入事件后5s触发。如果发生新事件,将取消旧任务并安排新任务,然后再等待5秒。

React的不同之处在于存储计算状态的位置,如_timeoutTask。文件范围,组件状态或组件实例。

由于_timeoutTask是组件级别,因此它应该是全局存储的。它不会影响渲染,因此也不会影响组件状态。所以我建议直接将它附加到组件实例。

答案 9 :(得分:0)

用户lodash javascript库并使用[_.debounce][1]

changeName: _.debounce(function (val) {
  console.log(val)                
}, 1000)

答案 10 :(得分:0)

我曾在一个项目中工作,我们在其中传递了大量数据以做出反应。键入每个字母后,数据原因滞后。我不能使用不受控制的输入,因为表单分散在5个不同的选项卡上,并且当您切换选项卡时,它失去了输入值。这是我所遇到的情况的排序版本。解决方案是更新状态不是在输入每个字母之后,而是在用户停止输入之后。为此,我们可以使用两种类型的输入,即受控输入和非受控输入,它们可以一起工作。

这可能会帮助下面的某个https://github.com/Pyot/react-update-state-on-stop-typing和代码示例:

import React, { Component } from 'react'

class ForHeavyData extends Component {
  state = {
    value: ''
  }

  timer = null

  handleChange = (e) => {
    clearTimeout(this.timer);
    let value = e.target.value;
    this.timer = setTimeout(() => { this.triggerChange(value) }, 2000);
  }

  triggerChange = (targetValue) => {
    this.setState({ value: targetValue })
  }

render() {

return (
  <div className={'container'}>
    <div className={'row'}>
      <div className={'col-md-6'}>
        <div className={"form-group"}>
          <label forHtml="exampleInputEmail1"></label>
          <input
            className={'form-control'}
            placeholder={'Please type text...'}
            defaultValue={this.state.value}
            onChange={this.handleChange}
            onKeyDown={this.handleKeyDown} />
          <small className={"form-text text-muted"}>You'll see what you type after 2sec when you stop typing below.</small>
        </div>
      </div>
    </div>
    <div className={'row'}>
      <div className={'col-md-6'}>
        <div className={'redborder'}>
          {this.state.value !== '' ? this.state.value : 'You will see updated state here'}
        </div>
      </div>
    </div>
  </div>
)
}
}
export default ForHeavyData

答案 11 :(得分:0)

这是一个工作组件模板,带有一些有用的参数,可以帮助您入门。

import React, { Component } from 'react'

const initialState = { results: [], value: '' }

export default class SearchBox extends Component {
  state = initialState
  timeout = null
  search_url = "https://example.com/search?q="
  min_query_length = 2
  timeout_duration = 300

  handleSearchChange = (e) => {
    let value = e.target.value
    clearTimeout(this.timeout);
    if (value.length < 1) {
        return this.setState(initialState) 
    } else {
        this.setState({ value })
        if (value.length>=this.min_query_length) {    
            this.timeout = setTimeout(this.search, this.timeout_duration);
        }
    }
  }

  search = () => {
    // assuming your results are returned as JSON
    fetch(`${this.search_url}${this.state.value}`)
    .then(res => res.json())
    .then(data => {
        this.setState({
            results: data,
        })
    })
  }

  render() {
    return (
          <input
            onChange={this.handleSearchChange}
          />
    )
  }
}

答案 12 :(得分:0)

使用反应钩子,从@anoNewb 的回答中修改。添加:

  • 在计时器仍在运行时防止多个触发器
  • 添加表单提交事件

codesandbox

    import React, { useState, useEffect } from "react";

    export default function App() {
      const [search, setSearch] = useState("");
      const [searchTimeout, setSearchTimeout] = useState(null);

      useEffect(() => {
        if (searchTimeout) {
          clearTimeout(searchTimeout);
        }

        setSearchTimeout(
          setTimeout(() => {
            loadUsers();
          }, 1000),
        );

        return () => clearTimeout(searchTimeout);
      }, [search]);

      const loadUsers = () => {
        console.log("axios call with query: ", search);
      };

      return (
        <div className="App">
          <form
            onSubmit={(e) => {
              e.preventDefault();
              if (searchTimeout) {
                clearTimeout(searchTimeout);
              }
              loadUsers();
            }}
          >
            <input
              onChange={(e) => {
                setSearch(e.target.value);
              }}
            />
          </form>
        </div>
      );
    }

答案 13 :(得分:0)

您可以使用 React 钩子 useEffect 和 setTimeOut 函数一起使用,因为它始终返回计时器 ID,您可以按如下方式轻松清除具有该 ID 的计时器

<div className="tableDataContainer">
    <div className="stickyHeader">
        <Table>
            <TableHead></TableHead>
        </Table>
    </div>
    <Table>
        <TableHead></TableHead>
        <TableBody></TableBody>
    </Table>
</div>

答案 14 :(得分:0)

对于 React 钩子:

首先我们将定义一个组件

import React, { useEffect, useState } from "react";

const SearchInputText = ({ value, name, placeholder, onChange }) => {
  // state for keepign search text 
  const [searchText, setSearchText] = useState(value);
  // state for keeping the timeout
  const [searchTextTimeout, setSearchTextTimeout] = useState(null);

  // handler for form submit (pressing enter without waiting for setimeout to trigger)
  const handleSubmit = (e) => {
    e.preventDefault();
    // clear timeout as it'll that would be triggered
    if (searchTextTimeout) {
      clearTimeout(searchTextTimeout);
    }
    onChange(searchText);
  };

  // onChange handler
  const handleOnChange = (e) => {
  // cancelling previous timeouts
    if (searchTextTimeout) {
      clearTimeout(searchTextTimeout);
    }
    // first update the input text as user type
    setSearchText(e.target.value);
    // initialize a setimeout by wrapping in our searchTextTimeout so that we can clear it out using clearTimeout
    setSearchTextTimeout(
      setTimeout(() => {
        onChange(searchText);
        // timeout is 2500ms, change it to less or more.
      }, 2500),
    );
  };

  // making sure that we clear the timeout if/when the component unmount
  useEffect(() => {
    return () => clearTimeout(searchTextTimeout);
  }, [searchTextTimeout]);

  return (
    <form onSubmit={handleSubmit}>
      <input
        name={name}
        placeholder={placeholder}
        type="text"
        value={searchText}
        onChange={handleOnChange}
      />
    </form>
  );
};

export default SearchInputText;

用法:

const Parent = () => {
  const handleChange = (e) => {
    // your implementation here
  };
  return (
    <div>
      <SortSearchInput name="search" placeholder="Enter Search" onChange={handleChange} />
    </div>
  );
};