输入状态的更改延迟一个字符(useState挂钩)

时间:2019-08-08 00:09:22

标签: reactjs input state react-hooks

我正在尝试对我的社交网络中的用户个人资料进行即时搜索。似乎可行,但是在输入更改上设置状态(使用挂钩)会导致延迟一个字符。

我研究了一下,发现状态延迟的问题可以通过在setState中使用回调函数来解决。但是,useState不支持。

这是我的输入元素:


<input
   type="text"
   placeholder="Enter your query"
   name="query"
   onChange={e => onChange(e)}
/>


这是我的状态和onChange处理程序:


const [filteredData, setFilteredData] = useState({
    query: "",
    filteredProfiles: profiles
  });


const onChange = e => {
    setFilteredData({
      query: e.target.value,
      filteredProfiles: profiles.filter(person =>
        person.user.name.includes(e.target.value)
      )
    });
    console.log(e.target.value); // outputs correct value immediately
    console.log(filteredData.query); // it's always one character late
    console.log(filteredData.filteredProfiles); //works but 1 char late as well
  };

3 个答案:

答案 0 :(得分:2)

  

总是迟到一个字符

控制台日志在上一个状态周期内,因此预计它要“延迟一个周期”。记住setState() is asynchronous

如果要记录当前更改,请使用useEffect钩子。

  useEffect(() => {
    console.log(filteredData.query); // not late
    console.log(filteredData.filteredProfiles); // same here!
  }, [filteredData]);

效果挂钩将监听当前filteredData的更改并将其记录下来。

我还建议将useCallback用于事件处理程序。 有关完整代码,请参见Code Sandbox

答案 1 :(得分:0)

您是否尝试过将函数传递给onChange处理程序而不是执行它?像这样的东西:

<input
   type="text"
   placeholder="Enter your query"
   name="query"
   onChange={onChange} // Here
/>

这样,您不会在每次渲染组件时都生成新函数,希望对您有所帮助。

答案 2 :(得分:0)

您是要在API中搜索此数据还是在搜索本地数据?关闭代码,似乎您正在搜索本地数据。

每次更改输入时,您都可以使用useEffect来搜索数据。这样,当前状态将用于查询。

它不起作用的原因是因为您试图设置状态并在相同的“动作”中使用该状态,这将不起作用。状态是“后面有1个字符”,因为它没有机会来更新自己的新结果。.useEffect可以帮助您。

此外,在这种情况下,您没有要使用 onChange={e => onChange(e)} ,但这并没有任何伤害...您可以只需 onChange={onChange} ,事件就会自动作为参数传递。

类似的事情应该有所帮助。

[CodePen Mirror]

//// SCROLL DOWN FOR REACT CODE
const apiData = [
  {
    userId: 1,
    id: 1,
    title: "delectus aut autem",
    completed: false
  },
  {
    userId: 1,
    id: 2,
    title: "quis ut nam facilis et officia qui",
    completed: false
  },
  {
    userId: 1,
    id: 3,
    title: "fugiat veniam minus",
    completed: false
  },
  {
    userId: 1,
    id: 4,
    title: "et porro tempora",
    completed: true
  },
  {
    userId: 1,
    id: 5,
    title: "laboriosam mollitia et enim quasi adipisci quia provident illum",
    completed: false
  },
  {
    userId: 1,
    id: 6,
    title: "qui ullam ratione quibusdam voluptatem quia omnis",
    completed: false
  },
  {
    userId: 1,
    id: 7,
    title: "illo expedita consequatur quia in",
    completed: false
  },
  {
    userId: 1,
    id: 8,
    title: "quo adipisci enim quam ut ab",
    completed: true
  }
];

function Searcher() {
  const [search, setSearch] = React.useState("et");
  const [results, setResults] = React.useState([]);

  React.useEffect(() => {
      let searchResults;
      if (search) {
        searchResults = apiData.filter(i => i.title.includes(search));
      }
      setResults(searchResults);
    }, [search]);

  const handleInput = e => {
    setSearch(e.target.value);
  };

  return (
    <div>
      <h4>Search Me!</h4>
      {/* You dont have to use "e=>handleInput(e)" in this scenario, but it
         doesn't hurt anything... */}
      <input type="text" value={search} onChange={e=>handleInput(e)} />
      <p>{search}</p>
      {search && results && results.length === 0 ? (
        <p>No results found!</p>
      ) : (
        <pre>{JSON.stringify(results, null, 2)}</pre>
      )}
    </div>
  );
}

ReactDOM.render(<Searcher />, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.6/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js"></script>