如何在不设置 React 应用程序状态的情况下在组件中执行更改?

菲米拉德

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

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()像这样调用跳过效果

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]);
}

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

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 元素时,如下所示:

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>

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

React Native:如何在不由用户再次更新的情况下在应用程序中进行更改?

如何在不覆盖 React 中的其他项目的情况下设置对象的状态

如何在我的应用程序中避免“无法在未安装的组件上执行 React 状态更新”错误?

如何在 React 应用程序中为不同的组件设置不同的背景颜色?

如何在不使用JSX的情况下在React Native中制作组件?

如何在不使用 Owl Carousel 2 组件的情况下在 React 中实现 Owl Carousel?

如何在不使用其他库的情况下在React组件中编写内联CSS?

如何在不捆绑Webpack-React应用程序的情况下加载外部配置文件?

React 应用程序渲染函数在设置状态之前执行?

如何在不使用REST框架的情况下在Django和React应用中实现分页?

如何在 React 应用程序中执行 Python 代码?

如何在不破坏 Rust 工具链的情况下在 XCode 中测试 iOS 应用程序?

如何在不滚动的情况下在移动Web应用程序上启动网页

如何在不渲染子组件的情况下根据子组件的大小更改React父组件的大小?

如何在不轮询内核的情况下在C程序中监视NIC状态(上/下)?

如何在不安装Ubuntu的情况下在Unity中测试应用程序?

如何在React中轻松设置兄弟组件的状态?

如何在不冻结应用程序的情况下在 C# 桌面应用程序中快速处理多个文件

如何在React中设置对象状态

检查 React Native 应用程序中的不活动状态

React:如何在 CRUD 应用程序中设置编辑功能以在保持 id 的同时切换整个组件

如何在不创建箭头函数的情况下在 React 中传递带有参数的函数作为 prop

React-Redux-如何在应用程序状态内设置字段?

如何在同构应用程序中将状态从DOM同步到我的React组件?

在React中,如何在Provider的值更改后设置状态?

如何在不重新渲染的情况下在基本应用程序组件中使用 GraphQL 钩子进行反应?

如何在不包含react的情况下通过npm发布基于react的组件?

如何在没有博览会的情况下发布 React Native 应用程序?

如何在没有外壳访问的情况下部署React应用程序?