Hooks are functions that can be called in functional components that allow you to use state and other React features without writing a class.
Commonly used hooks include the following:
- useState
- useEffect
- useRef
- useContext
- useReducer
This article focuses on how useRef can detect clicks outside elements
useRef
UseRef is a very powerful base hook. Here are three main application scenarios:
- Gets the DOM element node
- Gets an instance of the child component
- Data that shares data between render cycles (state cannot store data across render cycles because saving state triggers rerendering of components)
Here we use useRef to get the actual DOM node
The useRef function takes a variable for the initial value of ref and returns a REF object
const elementRef = useRef(null)
Copy the code
You then need to add the REF attribute value to the corresponding JSX node, which is the ref object returned by the call to useRef. In this case, you need to get the real DOM, just get the current property of ref
const DOM = elementRef.current;
Copy the code
Details are as follows:
function Index() {
const elementRef = useRef(null)
return (
<>
<div ref={elementRef}>
Hello World
</div>
</>)}Copy the code
The specific implementation
Let’s check to see if a click event occurred outside the element
Here are two scenarios where we need to check for clicks outside elements:
- When we create a popover, when we click on the popover, we need to close the popover
- When you create a
dropdown
When clickdropdown
Need to close it
Here’s a simple example:
function Index() {
const [isOpen, setIsOpen] = useState(true)
return (
<>
<div>
<h2>App with a Modal</h2>
<button onClick={()= > setIsOpen(true)}>Open Modal</button>
<div id="modal">
<Modal isOpen={isOpen}>Modal component content</Modal>
</div>
</>)}Copy the code
Click the button in the above component to show Modal. So our goal is to turn off Modal when you click outside of Modal.
Here’s how to do it:
-
Use ref to reference the Modal component
-
Detection of click
-
Verify that a click occurs outside of the Modal component
-
If a click occurs outside of the Modal component, setIsOpen(false)
Step 1: Reference Modal
First use useRef to reference the Modal node
function Index() {
const [isOpen, setIsOpen] = useState(false);
const modalRef = useRef();
return (
<>
<div>
<h2>App with a Modal</h2>
<button onClick={()= > setIsOpen(true)} type="button">
Open Modal
</button>
<div id="modal" ref={modalRef}>
<Modal isOpen={isOpen}>This is a Modal</Modal>
</div>
</div>
</>
);
}
Copy the code
When the current component is rendered, we can retrieve the DOM node via modalref.current
Step 2: Add global click event listeners
The second step adds an event listener globally
useEffect(() = > {
function handler(event) {
console.log(event, 'clicked somewhere')}window.addEventListener('click', handler)
return () = > window.removeEventListener('click', handler)
}, [])
Copy the code
We added click listening to Windows to listen for events on the entire page. Note that it is important to remove bound global events when a component is removed, otherwise it may cause memory leaks or unknown errors
Step 3: Check if a click occurs outside the element
When an Event is clicked, the input parameter to the callback function is the Event object, which contains a list of information about the clicked Event. If you want to get the currently clicked element, use event.target. The following checks if the modal element contains event.target:
useEffect(() = > {
function handler(event) {
if(! modalRef.current? .contains(event.target)) {console.log('clicked outside of the modal')}}window.addEventListener('click', handler)
return () = > window.removeEventListener('click', handler)
}, [])
Copy the code
Step 4: Turn off Modal when clicked outside of Modal
When detecting an out-of-modal click, execute setIsOpen(false) to close the popover
useEffect(() = > {
function handler(event) {
if(! modalRef.current? .contains(event.target)) {console.log('clicked outside of the modal')}}window.addEventListener('click', handler)
return () = > window.removeEventListener('click', handler)
})
Copy the code
To encapsulate the hooks
Let’s package the above functionality as a new hook:
export function useOnClickOutside(ref, callback) {
useEffect(() = > {
function handler(event) {
if(! ref.current? .contains(event.target)) { callback(); }}window.addEventListener('click', handler);
return () = > window.removeEventListener('click', handler)
}, [callback, ref]);
}
Copy the code
In the above hook, we need to pass in two arguments: ref: the ref object callback that needs to have the clickOutside effect: The callback function that triggers clickOutside has a listener event bound to the window that determines if the clicked element is in the ref corresponding DOM structure: if it is not, the callback that is passed in is triggered.
Below is a function that uses useOnClickOutside hook
function Index() {
const [isOpen, setIsOpen] = useState(false);
const ref = useRef(null);
useOnClickOutside(ref, () = > setIsOpen(false));
return (
<div>
<h2>App with ad Modal</h2>
<button type="button" onClick={()= > setIsOpen(false)}>
Open Modal
</button>
<div ref={ref} id="modal">
<Modal isOpen={isOpen}>This is a Modal</Modal>
</div>
</div>
);
}
Copy the code
In the above code, the same function is implemented. Add the following code that needs to be changed
useOnClickOutside(ref, () = > setIsOpen(false));
Copy the code
The use of useRef goes far beyond that. We usually use it to hold variables. Here’s how useRef and useState are used. In hooks, both useState and useRef can be used to hold variables, except that components are not rerendered when the value of useRef changes.
Github address: github.com/skychenbo/s… Welcome to attention