Open aliankarali opened 5 years ago
try this in the same file:
namespace Dropdown {
export let handleClickOutside: () => void;
}
thanks for the tip 👍
I tried this solution but typescript complains this:
Cannot redeclare block-scoped variable 'Dropdown'.
I also tried it and I get Duplicate identifier 'Dropdown'
.
react-onclickoutside v6.8.0, typescript v.3.3.4000
Third on the train, the create-react-app default linter doesn't like it
Failed to compile.
./src/components/MenuBar/MenuBar.tsx
Line 45: ES2015 module syntax is preferred over custom TypeScript modules and namespaces @typescript-eslint/no-namespace
Search for the keywords to learn more about each error.
not an error, but if someone could suggest an alternative solution, would be great.
As a solution you can get rid of this library and use this small hook from https://usehooks.com/useOnClickOutside/. It works for me really well:
import { useState, useEffect, useRef } from 'react';
// Usage
function App() {
// Create a ref that we add to the element for which we want to detect outside clicks
const ref = useRef();
// State for our modal
const [isModalOpen, setModalOpen] = useState(false);
// Call hook passing in the ref and a function to call on outside click
useOnClickOutside(ref, () => setModalOpen(false));
return (
<div>
{isModalOpen ? (
<div ref={ref}>
👋 Hey, I'm a modal. Click anywhere outside of me to close.
</div>
) : (
<button onClick={() => setModalOpen(true)}>Open Modal</button>
)}
</div>
);
}
// Hook
function useOnClickOutside(ref, handler) {
useEffect(
() => {
const listener = event => {
// Do nothing if clicking ref's element or descendent elements
if (!ref.current || ref.current.contains(event.target)) {
return;
}
handler(event);
};
document.addEventListener('mousedown', listener);
document.addEventListener('touchstart', listener);
return () => {
document.removeEventListener('mousedown', listener);
document.removeEventListener('touchstart', listener);
};
},
// Add ref and handler to effect dependencies
// It's worth noting that because passed in handler is a new ...
// ... function on every render that will cause this effect ...
// ... callback/cleanup to run every render. It's not a big deal ...
// ... but to optimize you can wrap handler in useCallback before ...
// ... passing it into this hook.
[ref, handler]
);
}
Thanks for the hooks @bogem ;) For those looking for an external solution I would recommend https://github.com/airbnb/react-outside-click-handler
Defining the handler on the function after its definition worked for me. I think it's ok, as its value will be set on rendering the component anyways.
import {useState} from 'react'
import onClickOutside from 'react-onclickoutside'
const UserInfo = () => {
const [menuVisible, setMenuVisible] = useState(false)
UserInfo.clickOutside = () => setMenuVisible(false)
return (
<div className="cursor-pointer"
onClick={() => setMenuVisible(!menuVisible)}
>
<p>Click me</p>
<div className={!menuVisible && 'hidden'}>
<p>I am zee menu</p>
<p>I am zee menu</p>
</div>
</div>
)
}
UserInfo.clickOutside = null /// !! this
export default onClickOutside(UserInfo, {
handleClickOutside: () => UserInfo.clickOutside,
})
Just a note: if you've already written the code to make hooks work, PRs that add a hook solution are most certainly welcome, and I'll be more than happy to push out a new version.
Update: Another thing I noticed with this pattern is that when you have multiple instances of the same Component, only the last one triggers handleClickOutside.
Here is my code, grossly simplified (sorry if it is more of a TS question rather than this library, but in any way it would be nice to see an example).
error: Property 'handleClickOutside' does not exist on type '({ options, }: Props) => Element'. ts(2339)
The code works fine but in the editor Dropdown.handleClickOutside lines highlights this error. Other than using // @ts-ignore, how can I solve this issue? how can I specify the property?