”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > React 中的智能下拉菜单:使用 useReducer 和 useRef 进行外部点击处理

React 中的智能下拉菜单:使用 useReducer 和 useRef 进行外部点击处理

发布于2024-11-03
浏览:323

Smart Dropdowns in React: Using useReducer and useRef for Outside Click Handling

如何使用 useReducer 和 useRef 在 React 中使用 Tailwind CSS 创建下拉菜单

在 React 应用程序中创建下拉菜单可以通过提供一种紧凑的方式来导航和访问附加信息,从而增强用户体验。在本指南中,我们将实现两个下拉菜单,一个用于通知,一个用于用户配置文件设置,使用 useReducer 进行状态管理,使用 useRef 处理外部点击以关闭下拉菜单。我们还将合并 Font Awesome 图标,以获得精美的外观。

介绍

在现代 Web 开发中,有效管理用户界面至关重要。 React 与 Tailwind CSS 相结合,提供了用于构建响应式组件的强大工具包。我们将学习如何在 React 中处理下拉菜单功能,确保单击下拉菜单外部将关闭它,同时保持独立打开或关闭每个下拉菜单的能力。

useReducer 和 useRef 是什么?

在深入代码之前,让我们先了解一下我们将使用的两个 React hook:

  • useReducer:此钩子是 useState 的替代方案,用于管理功能组件中的状态。它对于管理复杂的状态逻辑和多个状态变量特别有用。 useReducer 钩子接受一个减速器函数和一个初始状态,返回当前状态和一个调度函数来更新该状态。

  • useRef:这个钩子提供了一种直接引用 DOM 元素的方法。它对于访问和操作元素而不触发重新渲染非常有用。在我们的例子中,我们将使用 useRef 来检查点击是否发生在下拉菜单之外。

逐步实施

第 1 步:设置项目

首先,确保您有一个使用 Tailwind CSS 设置的 React 项目。如果没有,可以使用 Create React App 创建它:

npx create-react-app my-dropdown-app
cd my-dropdown-app
npm install tailwindcss
npx tailwindcss init

通过将以下行添加到 tailwind.config.js 来配置 Tailwind:

module.exports = {
  purge: ['./src/**/*.{js,jsx,ts,tsx}', './public/index.html'],
  darkMode: false,
  theme: {
    extend: {},
  },
  variants: {
    extend: {},
  },
  plugins: [],
};

然后,将 Tailwind 指令添加到您的 index.css 中:

@tailwind base;
@tailwind components;
@tailwind utilities;

第 2 步:安装 Font Awesome

要使用Font Awesome图标,您需要安装@fortawesome/react-fontawesome包:

npm install @fortawesome/react-fontawesome @fortawesome/free-solid-svg-icons

第三步:创建导航栏组件

在 src 目录中,创建一个名为 Navbar.tsx 的新文件。该组件将包含下拉菜单。

实施导航栏代码

这是 Navbar 组件的代码,它利用 useReducer 和 useRef 来处理下拉状态和外部点击。

import React, { useRef, useEffect, useReducer } from "react";
import { Link } from "react-router-dom";
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faBell, faUser, faCaretDown } from '@fortawesome/free-solid-svg-icons';

interface IState {
  isProfileOpen: boolean;
  isNotificationOpen: boolean;
}

type Action =
  | { type: 'toggleProfile' }
  | { type: 'toggleNotification' }
  | { type: 'closeAll' };

function reducer(state: IState, action: Action): IState {
  switch (action.type) {
    case 'toggleProfile':
      return {
        isProfileOpen: !state.isProfileOpen,
        isNotificationOpen: false
      };
    case 'toggleNotification':
      return {
        isProfileOpen: false,
        isNotificationOpen: !state.isNotificationOpen
      };
    case 'closeAll':
      return {
        isProfileOpen: false,
        isNotificationOpen: false
      };
    default:
      return state;
  }
}

const Navbar: React.FC = () => {
  const [state, dispatch] = useReducer(reducer, { isProfileOpen: false, isNotificationOpen: false });
  const profileDropdownRef = useRef(null);
  const notificationDropdownRef = useRef(null);

  useEffect(() => {
    const handleClickOutside = (event: MouseEvent) => {
      const target = event.target as Node;

      if (
        (profileDropdownRef.current && !profileDropdownRef.current.contains(target)) ||
        (notificationDropdownRef.current && !notificationDropdownRef.current.contains(target))
      ) {
        dispatch({ type: 'closeAll' });
      }
    };

    document.addEventListener("mousedown", handleClickOutside);
    return () => {
      document.removeEventListener("mousedown", handleClickOutside);
    };
  }, []);

  const toggleProfileDropdown = (event: React.MouseEvent) => {
    event.stopPropagation();
    dispatch({ type: 'toggleProfile' });
  };

  const toggleNotificationDropdown = (event: React.MouseEvent) => {
    event.stopPropagation();
    dispatch({ type: 'toggleNotification' });
  };

  const closeDropdowns = () => {
    dispatch({ type: 'closeAll' });
  };

  const notificationItems = [
    { text: "New data received", time: "2 Days Ago" },
    { text: "New update available", time: "1 Day Ago" },
    { text: "Scheduled maintenance", time: "3 Days Ago" },
  ];

  const profileItems = [
    { label: "Profile", link: "#" },
    { label: "Settings", link: "#" },
    { label: "Logout", link: "#" }
  ];

  return (
    
); }; export default Navbar;

第 4 步:将导航栏集成到您的应用程序中

打开您的 App.tsx 文件并导入 Navbar 组件以将其包含在您的应用程序布局中。

import React from 'react';
import { BrowserRouter as Router } from 'react-router-dom';
import Navbar from './components/Navbar';

const App: React.FC = () => {
  return (
    
      
      

Welcome to DC Dashboard!

{/* Other components and content */}
); }; export default App;

第 5 步:使用 Tailwind CSS 进行样式设置

Tailwind CSS 提供的类应该已经给出了简洁的设计。但是,请随意根据需要自定义样式。

第 6 步:测试应用程序

通过运行以下命令启动您的应用程序:

bash
npm start

您现在应该在应用程序顶部看到一个导航栏,其中包含通知和用户配置文件设置的功能下拉菜单。

常问问题

1。本例中 useReducer 钩子如何工作?

useReducer 钩子允许我们有效地管理多个下拉菜单的状态。我们定义一个reducer函数,它接受当前状态和返回新状态的操作。此模式有助于切换下拉菜单和处理立即关闭所有下拉菜单的逻辑。

2.为什么使用useRef?

我们使用 useRef 来引用下拉元素。这让我们可以检查点击事件是否发生在这些元素之外。如果是这样,我们会发送一个操作来关闭下拉菜单,以确保干净的用户体验。

3.我可以添加更多下拉菜单吗?

是的!您可以扩展减速器中的状态并类似地添加更多下拉菜单。只需确保每个下拉菜单都有自己的引用和切换功能。

4。此实现是否需要 Tailwind CSS?

不,Tailwind CSS 不是强制性的。您可以使用任何 CSS 框架或自定义 CSS 样式来设置下拉菜单的样式,但 Tailwind 使样式设置更快、响应更灵敏。

结论

在本指南中,您学习了如何使用 useReducer 进行状态管理和 useRef 处理外部点击,在 React 中创建功能性下拉菜单。这种方法提供了一种干净高效的方式来管理复杂的 UI 交互,从而增强整体用户体验。您可以在此基础上随意构建并自定义它以满足您的应用程序的需求!

版本声明 本文转载于:https://dev.to/chintanonweb/smart-dropdowns-in-react-using-usereducer-and-useref-for-outside-click-handling-138h?1如有侵犯,请联系[email protected]删除
最新教程 更多>

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3