"일꾼이 일을 잘하려면 먼저 도구를 갈고 닦아야 한다." - 공자, 『논어』.
첫 장 > 프로그램 작성 > React의 스마트 드롭다운: 외부 클릭 처리를 위해 useReducer 및 useRef 사용

React의 스마트 드롭다운: 외부 클릭 처리를 위해 useReducer 및 useRef 사용

2024-11-03에 게시됨
검색:521

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

useReducer 및 useRef를 사용하여 Tailwind CSS로 React에서 드롭다운을 만드는 방법

React 애플리케이션에서 드롭다운 메뉴를 생성하면 추가 정보를 탐색하고 액세스할 수 있는 간단한 방법을 제공하여 사용자 경험을 향상할 수 있습니다. 이 가이드에서는 상태 관리를 위해 useReducer를 사용하고 드롭다운을 닫기 위해 외부 클릭을 처리하는 데 useRef를 사용하여 두 개의 드롭다운(알림용과 사용자 프로필 설정용)을 구현합니다. 또한 세련된 모양을 위해 Font Awesome 아이콘을 통합할 것입니다.

소개

현대 웹 개발에서는 사용자 인터페이스를 효율적으로 관리하는 것이 중요합니다. Tailwind CSS와 결합된 React는 반응형 구성 요소를 구축하기 위한 강력한 도구 키트를 제공합니다. 각 드롭다운을 독립적으로 열거나 닫는 기능을 유지하면서 드롭다운 외부를 클릭하면 드롭다운이 닫히도록 React에서 드롭다운 기능을 처리하는 방법을 알아봅니다.

useReducer와 useRef는 무엇인가요?

코드를 살펴보기 전에 우리가 사용할 두 가지 React 후크를 이해해 보겠습니다.

  • 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: [],
};

그런 다음 index.css에 Tailwind 지시어를 추가하세요.

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

2단계: Font Awesome 설치

Font Awesome 아이콘을 사용하려면 @fortawesome/react-fontawesome 패키지를 설치해야 합니다:

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

3단계: Navbar 구성요소 생성

src 디렉터리에 Navbar.tsx라는 새 파일을 만듭니다. 이 구성요소에는 드롭다운이 포함됩니다.

Navbar 코드 구현

다음은 useReducer 및 useRef를 활용하여 드롭다운 상태 및 외부 클릭을 처리하는 Navbar 구성 요소의 코드입니다.

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단계: 앱에 Navbar 통합

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

이제 애플리케이션 상단에 알림 및 사용자 프로필 설정을 위한 기능 드롭다운이 포함된 탐색 모음이 표시됩니다.

FAQ

1. 이 예에서 useReducer 후크는 어떻게 작동합니까?

useReducer 후크를 사용하면 여러 드롭다운 상태를 효율적으로 관리할 수 있습니다. 현재 상태를 취하는 리듀서 함수와 새 상태를 반환하는 동작을 정의합니다. 이 패턴은 드롭다운을 전환하고 모든 드롭다운을 한 번에 닫는 논리를 처리하는 데 유용합니다.

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에서 복제됩니다. 침해가 있는 경우, 문의 Study_golang@163 .comdelete
최신 튜토리얼 더>

부인 성명: 제공된 모든 리소스는 부분적으로 인터넷에서 가져온 것입니다. 귀하의 저작권이나 기타 권리 및 이익이 침해된 경우 자세한 이유를 설명하고 저작권 또는 권리 및 이익에 대한 증거를 제공한 후 이메일([email protected])로 보내주십시오. 최대한 빨리 처리해 드리겠습니다.

Copyright© 2022 湘ICP备2022001581号-3