如何重置自定义useOutsideClick Hook至初始状态?
useOutsideClick Hook to Its Initial State Got it, let's work through this problem. Your current useOutsideClick hook tracks whether a click happened outside the referenced component, but right now there’s no way to manually reset its internal clickOutside state from the parent component. Here are two straightforward, practical approaches to fix this:
Approach 1: Expose a Reset Function from the Hook
Modify the hook to return both the clickOutside state and a dedicated reset function. This gives your parent component direct control to trigger a reset whenever needed.
Updated useOutsideClick Hook:
import { useEffect, useState } from 'react'; const useOutsideClick = (ref) => { const [clickOutside, setClickOutside] = useState(false); // Reset function to set state back to initial value const resetOutsideClick = () => { setClickOutside(false); }; useEffect(() => { const handleClick = (e) => { ref.current?.contains(e.target) ? setClickOutside(false) : setClickOutside(true); }; document.addEventListener('click', handleClick); return () => document.removeEventListener('click', handleClick); }, [ref]); // Return both the state and the reset function return [clickOutside, resetOutsideClick]; }; export default useOutsideClick;
Usage in App Component:
Destructure the reset function and call it right after handling the outside click logic:
import { useState, useRef, useEffect } from 'react'; import useOutsideClick from './useOutsideClick'; const App = () => { const [activeComponent, setActiveComponent] = useState(null); const dropDownRef = useRef(); // Destructure the state and reset function from the hook const [outsideClick, resetOutsideClick] = useOutsideClick(dropDownRef); useEffect(() => { if (outsideClick) { setActiveComponent('WhatAreYouWorkingOn'); // Trigger the reset to set clickOutside back to false resetOutsideClick(); } }, [outsideClick, setActiveComponent, resetOutsideClick]); return ( <div className='DropDown' ref={dropDownRef}> {/* Your dropdown content goes here */} </div> ); }; export default App;
Approach 2: Add a Reset Trigger Prop to the Hook
If you prefer a more declarative approach, add a resetTrigger prop to the hook. When this prop changes, the hook will automatically reset its internal state.
Updated useOutsideClick Hook:
import { useEffect, useState } from 'react'; const useOutsideClick = (ref, resetTrigger) => { const [clickOutside, setClickOutside] = useState(false); // Reset state whenever the resetTrigger value changes useEffect(() => { if (resetTrigger) { setClickOutside(false); } }, [resetTrigger]); useEffect(() => { const handleClick = (e) => { ref.current?.contains(e.target) ? setClickOutside(false) : setClickOutside(true); }; document.addEventListener('click', handleClick); return () => document.removeEventListener('click', handleClick); }, [ref]); return clickOutside; }; export default useOutsideClick;
Usage in App Component:
Add a state variable to act as the trigger, and toggle it when you need to reset the hook:
import { useState, useRef, useEffect } from 'react'; import useOutsideClick from './useOutsideClick'; const App = () => { const [activeComponent, setActiveComponent] = useState(null); const [resetOutsideTrigger, setResetOutsideTrigger] = useState(false); const dropDownRef = useRef(); const outsideClick = useOutsideClick(dropDownRef, resetOutsideTrigger); useEffect(() => { if (outsideClick) { setActiveComponent('WhatAreYouWorkingOn'); // Toggle the trigger to trigger the hook's reset logic setResetOutsideTrigger(prev => !prev); } }, [outsideClick, setActiveComponent]); return ( <div className='DropDown' ref={dropDownRef}> {/* Your dropdown content goes here */} </div> ); }; export default App;
Why This Works
The original hook’s internal state is encapsulated, so we can’t modify it directly from the parent component. By either exposing a reset function or adding a trigger prop, we create a controlled way to communicate the reset request from the parent to the hook. Both approaches are valid—pick whichever fits better with your component’s pattern!
内容的提问来源于stack exchange,提问作者Erik Martín Jordán

