使用受控输入组件反应 useState Hook 问题

React useState Hook issue with controlled input component

我的应用程序中有一个受控的 class 组件,我想将其变成一个使用挂钩的功能组件。之前,通过在输入中设置 event.target.value 并将 searchTerm 的状态设置为当前值,代码可以正常工作。然而,自从用钩子重构后,我注意到 searchTerm 状态值是每个 event.target.value 之前的字母的问题。例如,如果我在输入栏中键入 "Joker",使用 setSearchTerm(e.target.value),我会得到 searchTerm 状态为 "Joke" 而不是 "Joker",直到我通过点击钥匙。我不确定为什么会这样,因为当我使用 class 组件执行此操作时,将 this.state.searchTerm 设置为 e.target.value 将实现预期目标。之前如果我在输入字段中输入 "Joker",searchTerm 状态实际上是 "Joker"。对此的任何帮助将不胜感激。谢谢!

import React, { useState, useRef } from 'react';
import './SearchBar.styles.scss';
import FontAwesome from 'react-fontawesome';
import {connect} from 'react-redux';
import {searchMovies} from '../../redux/redux-home/home.actions';

const SearchBar = ({ searchMovies }) => {
    const [searchTerm, setSearchTerm] = useState('');
    // constructor(){
    //     super();
    //     this.state={
    //         searchTerm: ''
    //     }
    // }

    const timeOut = useRef(null);

    const doSearch = e => {
        clearTimeout(timeOut.current);
        setSearchTerm(e.target.value);
        // this.setState({[e.target.name]: e.target.value});

        timeOut.current = setTimeout(() => {
            searchMovies(searchTerm);
        }, 500);
    }
    return(
        <div className="searchbar">
            <div className="searchbar-content">
                <FontAwesome className="fa-search" name="search" size="2x"/>
                <input type="text" placeholder="Movie" autoComplete="off" onChange={doSearch} value={searchTerm}/>
            </div>
        </div>
    );
}
const mapDispatchToProps = dispatch => ({
    searchMovies: search => dispatch(searchMovies(search))
});

export default connect(null, mapDispatchToProps)(SearchBar);

Console.log(e.target.value);setSearchTerm行前后都是return的正确值;但是,setSearchTerm 行前后的 console.log(searchTerm); 都是 return 不正确的值,这是一个事件触发的原因。

function App() {
  const [value, setValue] = useState('');

  const timeOut = useRef(null);

  const change = (e) => {
    clearTimeout(timeOut.current);
    setValue(e.currentTarget.value)
    timeOut.current = setTimeout(() => {
      //see the diffetrence here
       console.log('hello', value, e.currentTarget.value)
  }, 500);
    console.log(e.target.value)
  }
  return (
    <div className="App">
      <input onChange={change} value={value} />
    </div>
  );
}

import React, { useState, useRef } from 'react';
import './SearchBar.styles.scss';
import FontAwesome from 'react-fontawesome';
import {connect} from 'react-redux';
import {searchMovies} from '../../redux/redux-home/home.actions';

const SearchBar = ({ searchMovies }) => {
    const [searchTerm, setSearchTerm] = useState('');
    // constructor(){
    //     super();
    //     this.state={
    //         searchTerm: ''
    //     }
    // }

    const timeOut = useRef(null);

    const doSearch = e => {
        clearTimeout(timeOut.current);
        setSearchTerm(e.target.value);
        // this.setState({[e.target.name]: e.target.value});

        timeOut.current = setTimeout(() => {
         // -----------------------------------
         console.log(searchTerm, e.currentTarget.value)
            searchMovies(searchTerm);
        }, 500);
    }
    return(
        <div className="searchbar">
            <div className="searchbar-content">
                <FontAwesome className="fa-search" name="search" size="2x"/>
                <input type="text" placeholder="Movie" autoComplete="off" onChange={doSearch} value={searchTerm}/>
            </div>
        </div>
    );
}
const mapDispatchToProps = dispatch => ({
    searchMovies: search => dispatch(searchMovies(search))
});

export default connect(null, mapDispatchToProps)(SearchBar);

您需要使用useEffect来监控searchTerm的变化:

useEffect(() => {
    // This will be called after searchTerm has been updated
    if (!searchTerm) return;
    clearTimeout(timeOut.current);
    timeOut.current = setTimeout(() => {
        searchMovies(searchTerm);
    }, 500);
}, [searchTerm]);

const doSearch = e => {
    // Just update the state, and let useEffect handle it
    setSearchTerm(e.target.value);
}