简体   繁体   中英

What is the correct way to handle a key event using useEffect() hook which on the other hand triggers local state changes?

Pretty new to React Hooks and I ran into this issue. I have a functional component that takes an input and sends it to the parent component when I hit the enter key (keycode = 13). The component looks something like this.

const SearchTermBar = (props) => {
const {resetStateSearchTerm, handlePowerToggleParent} = props;
const [inputTerm, handleInputChange] = useState('');
const inputRef = useRef();

useEffect(() => {
    const keyPressEvent = (e) => {
        if (e.keyCode === 13) {
            resetStateSearchTerm(inputTerm);
            handleInputChange('');
            handlePowerToggleParent('search');
        }
    };

    inputRef.current.addEventListener('keydown', keyPressEvent);
    let parentInputRef = inputRef;

    return () => {
        console.log('remove event listener');
        parentInputRef.current.removeEventListener('keydown', keyPressEvent);
    }
}, [inputTerm, resetStateSearchTerm, handlePowerToggleParent]);

return (
    <div className='SearchTermBar'>
        <input
            type='text'
            placeholder='Enter search term here (Press return to confirm)'
            className='SearchTermBar__Input'
            value={inputTerm}
            onChange={(e) => handleInputChange(e.target.value)}
            ref={inputRef}
        />
    </div>
);

The problem is that the event is registered and unregistered every time the inputTerm or props value changes. But I am not able to figure out the correct way to handle the event registration/removal (which should happen once ideally) I understand it is because of the dependency on the inputTerm but I would like to know a better solution to this problem.

You already has the input ref, you don't really need a state:

const NOP = () => {};
const DEFAULT_INPUT = "";

function SearchTermBar(props) {
  const { resetStateSearchTerm = NOP, handlePowerToggleParent = NOP } = props;
  const inputRef = useRef();

  useEffect(() => {
    const keyPressEvent = (e) => {
      if (e.keyCode === 13) {
        resetStateSearchTerm(inputRef.current.value);
        inputRef.current.value = DEFAULT_INPUT;
        handlePowerToggleParent("search");
      }
    };

    inputRef.current.addEventListener("keydown", keyPressEvent);
    let parentInputRef = inputRef;

    return () => {
      console.log("remove event listener");
      parentInputRef.current.removeEventListener("keydown", keyPressEvent);
    };
  }, [resetStateSearchTerm, handlePowerToggleParent]);

  return (
    <input
      type="text"
      placeholder="Enter search term here (Press return to confirm)"
      style={{ width: "50%" }}
      ref={inputRef}
    />
  );
}

Either way, if you want to keep the state, its value should be duplicated into a ref to fix the closure in the useEffect . It can be done by adding another useEffect which will update the mentioned ref.

编辑 hardcore-gates-iyffi

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM