【问题标题】:Changing state for input is delayed by one character (useState hook)更改输入的状态会延迟一个字符(useState 挂钩)
【发布时间】: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
  };

【问题讨论】:

  • 不是迟到一个字符,是为这次渲染准备的值,下一个值是为下一次渲染准备的

标签: reactjs input state react-hooks


【解决方案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
      猜你喜欢
      • 1970-01-01
      • 2021-03-06
      • 2021-01-27
      • 2020-05-31
      • 1970-01-01
      • 2021-04-10
      • 1970-01-01
      • 1970-01-01
      • 2021-05-28
      相关资源
      最近更新 更多