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

Posted

技术标签:

【中文标题】更改输入的状态会延迟一个字符(useState 挂钩)【英文标题】:Changing state for input is delayed by one character (useState hook) 【发布时间】:2019-12-15 15:16:48 【问题描述】:

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

我研究了一下,发现这个状态延迟问题可以通过在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
  ;

【问题讨论】:

不是迟到一个字符,是为这次渲染准备的值,下一个值是为下一次渲染准备的 【参考方案1】:

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

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

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

【讨论】:

【参考方案2】:

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

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

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

另外,你没有使用 onChange=e =&gt; 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>

【讨论】:

【参考方案3】:

总是迟到一个字符

控制台日志位于前一个状态周期内,因此预计会晚“一个周期”。记住setState() is asynchronous

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

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

效果挂钩将侦听当前的filteredData 更改并记录它。

我还建议将useCallback 用于事件处理程序。

【讨论】:

值得补充的是,state中的那个值是当前渲染的,nextValue是下一次渲染的,如果要在当前渲染中使用nextValue,则需要useEffect

以上是关于更改输入的状态会延迟一个字符(useState 挂钩)的主要内容,如果未能解决你的问题,请参考以下文章

通过延迟一个字符的相同值更新文本输入状态和AJAX搜索[重复]

useState 函数在功能组件中不起作用

React hooks - useState() 中的状态在路由更改时不会重置

useState 设置方法不会立即反映更改

如何使用 useState 挂钩更新状态而不重新渲染

在通过 useState() 更改状态后,我的祖父母没有使用新变量重新呈现查询并显示新数据