如何在不设置 React 应用程序状态的情况下在组件中执行更改? [英] How to execute change in a component without setting state in a react app?

查看:63
本文介绍了如何在不设置 React 应用程序状态的情况下在组件中执行更改?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果按下左右箭头键,下面的组件将设置状态.因为每个按键都会执行两个设置状态,所以会导致一些性能问题.如何在不设置状态或仅设置一种状态的情况下更改按键?

The component below Will set state if right or left arrow key is pressed. because each pressing key executes two set states, it will leads some performance issues. How can I get change in pressing keys without setting states or with just one set state?

import { useState, useEffect } from "react";


export function useKeyPress(targetKey) {
  const [keyPressed, setKeyPressed] = useState(false)
  
  function downHandler({ key }) {
    if (key === targetKey) {
      setKeyPressed(true);
    }
  }
  
  const upHandler = ({ key }) => {
    if (key === targetKey) {
      setKeyPressed(false);
    }
  }
  
  useEffect(() => {
    window.addEventListener("keydown", downHandler);
    window.addEventListener("keyup", upHandler);
    
    return () => {
      window.removeEventListener("keydown", downHandler);
      window.removeEventListener("keyup", upHandler);
    }
  })
  
  return keyPressed
}

推荐答案

如果你总是需要 keyPressed 的当前值,设置状态是没有办法的,但是你可以 通过指定依赖列表来跳过效果 并调用 useRef() 之类的这个:

If you always need the current value of keyPressed, there's no getting around setting state, but you can skip the effect by specifying the dependency list and calling useRef() like this:

export function useEventListener(targetRef, type, handler) {
  const handlerRef = useRef(null);

  useEffect(() => {
    handlerRef.current = handler;
  }, [handler]);

  useEffect(() => {
    const target = targetRef.current;
    const listener = (event) => handlerRef.current(event);

    target.addEventListener(type, listener);

    return () => {
      target.removeEventListener(type, listener);
    };
  }, [targetRef, type]);
}

然后你可以像这样定义你的函数:

And then you can define your function like this:

export function useKeyPress(targetKey) {
  const [keyPressed, setKeyPressed] = useState(false);
  const windowRef = useRef(window);

  useEventListener(windowRef, 'keydown', ({ key }) => {
    if (key === targetKey) {
      setKeyPressed(true);
    }
  });

  useEventListener(windowRef, 'keyup', ({ key }) => {
    if (key === targetKey) {
      setKeyPressed(false);
    }
  });

  return keyPressed;
}

虽然在上面的特定示例中,targetRef 参数起初可能看起来很迂回,但它非常有用,例如当您想将事件侦听器添加到 JSX 元素时,如下所示:

While the targetRef parameter may seem roundabout at first in the particular example above, it's very useful for instance when you want to add event listeners to JSX elements like this:

const { useEffect, useRef } = React;

function useEventListener(targetRef, type, handler) {
  const handlerRef = useRef(null);

  useEffect(() => {
    handlerRef.current = handler;
  }, [handler]);

  useEffect(() => {
    const target = targetRef.current;
    const listener = (event) => handlerRef.current(event);

    target.addEventListener(type, listener);

    return () => {
      target.removeEventListener(type, listener);
    };
  }, [targetRef, type]);
}

function App() {
  const buttonRef = useRef(null);

  useEventListener(buttonRef, 'click', () => {
    console.log('button clicked');
  });

  return (
    <button ref={buttonRef}>Click Me</button>
  );
}

ReactDOM.render(<App />, document.getElementById('root'));

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>

这篇关于如何在不设置 React 应用程序状态的情况下在组件中执行更改?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆