4 custom react hooks that will make your development easier
Tags: react, hooks, 100daysofcode
Published: 2021-08-30 10:49:51

## 1. useToggle
Basically, what this hook does is that, it takes a parameter with value true or false and toggles that value to opposite. It's useful when we want to take some action into it's opposite action.

**For example;** 
- show and hide modal, 
- show more/show less text, 
- open/close side menu.

```jsx
// Hook
// Parameter is the boolean, with default "false" value
const useToggle = (initialState = false) => {
    // Initialize the state
    const [state, setState] = useState(initialState);
    
    // Define and memorize toggler function in case we pass down the comopnent,
    // This function change the boolean value to it's opposite value
    const toggle = useCallback(() => setState(state => !state), []);
    
    return [state, toggle]
}

// Usage
function App() {
    // Call the hook which returns, current value and the toggler function
    const [isTextChanged, setIsTextChanged] = useToggle();
    
    return (
      <button onClick={setIsTextChanged}>
				{isTextChanged ? 'Toggled' : 'Click to Toggle'}
			</button>
    );
}
```

## 2. useOnClickOutside
This hook allows you to detect clicks outside of a specified element. 

By abstracting this logic out into a hook we can easily use it across all of our components that need this kind of functionality.

**For Example;**
- dropdown menus,
- tooltips,
- modals
- etc..

```jsx
// Hook
const 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);
      };
    },

    [ref, handler]
  );
}
```

```jsx
// 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>
  );
}
```

## 3. useSubmit

Instead of recreating  loading and form states we can also move that logic inside a hook called useSubmit

```jsx
// Hook
const useSubmit = submitFunction => {
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

	const handleSubmit = async () => {
    try {
      setLoading(true);
      setError(null);
      await submitFunction();
    } catch (error) {
      setError(error);
    } finally {
      setLoading(false);
    }
  };

  return [handleSubmit, loading, error];
};
```

```jsx
// Usage
function App() {
	const mySubmitFunction = () => {
	  return new Promise((resolve, reject) => {
	    setTimeout(() => {
				resolve("Timeout Finished")
	    }, 2000);
	  });
	};
	const [handleSubmit, loading, error] = useSubmit(mySubmitFunction);

	return (
	    <div className="App">
	      <button onClick={handleSubmit} disabled={loading}>
	        {!loading ? "Click me" : "Loading..."}
	      </button>
	      {error && <div>{error}</div>}
	    </div>
	  );
}
```

## 4. useMediaQuery
If you want to write css in js or you just want to add some sideEffect to the specific device or breakpoint this hook is for you.

```jsx
// Hook
const useMediaQuery = (query = "(min-width: 576px)") => {
  const [matches, setMatches] = useState(false);

  useEffect(() => {
    const media = window.matchMedia(query);
    if (media.matches !== matches) {
      setMatches(media.matches);
    }
    const listener = () => {
      setMatches(media.matches);
    };
    media.addListener(listener);
    return () => media.removeListener(listener);
  }, [matches, query]);

  return matches;
}

// Usage
const isTablet = useMediaQuery("(max-width: 1200px)");
```


## Links

- [useHooks](https://usehooks.com/)

- [useHooks(🔥).ts](https://usehooks-typescript.com/)

- [30 seconds of code](https://www.30secondsofcode.org/)

- [In reactJS, how to copy text to clipboard?](https://stackoverflow.com/questions/39501289/in-reactjs-how-to-copy-text-to-clipboard)