├── README.md ├── useArray.js ├── useCountDownTimer.js ├── useFetch.js ├── useInputState.js ├── useLocalStorage.js ├── usePageBottom.js ├── useToggleHook.js ├── useUserStatus.js └── usefulHooks.js /README.md: -------------------------------------------------------------------------------- 1 | # react-custom-hooks -------------------------------------------------------------------------------- /useArray.js: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | 3 | const useArray = (initialValue) => { 4 | const [array, setArray] = useState(initialValue); 5 | 6 | const pushIntoArray = (newElement) => { 7 | setArray((theArray) => [...theArray, newElement]); 8 | }; 9 | 10 | const updateArray = (index, newElement) => { 11 | setArray((theArray) => [ 12 | ...theArray.slice(0, index), 13 | newElement, 14 | ...theArray.slice(index + 1, theArray.length), 15 | ]); 16 | }; 17 | 18 | const removeFromArray = (index) => { 19 | setArray((theArray) => [ 20 | ...theArray.slice(0, index), 21 | ...theArray.slice(index + 1, theArray.length), 22 | ]); 23 | }; 24 | 25 | const clearArray = () => setArray([]); 26 | 27 | return [array, setArray, pushIntoArray, updateArray, removeFromArray, clearArray]; 28 | }; 29 | 30 | export { useArray }; 31 | -------------------------------------------------------------------------------- /useCountDownTimer.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useRef, useState } from "react"; 2 | 3 | const useCounter = (start, end) => { 4 | const [count, setCount] = useState(start); 5 | const timer = useRef(); 6 | 7 | //start the count down 8 | useEffect(() => { 9 | if (start > end) { 10 | timer.current = setInterval(() => { 11 | setCount((count) => count - 1); 12 | }, 1000); 13 | } 14 | return () => clearInterval(timer.current); 15 | }, []); 16 | 17 | //stop the timer once end value is reached 18 | useEffect(() => { 19 | if (count === end) { 20 | clearInterval(timer.current); 21 | } 22 | }, [count, end]); 23 | 24 | //update count when start value gets updated 25 | useEffect(() => { 26 | setCount(start); 27 | }, [start]); 28 | 29 | return count; 30 | }; 31 | -------------------------------------------------------------------------------- /useFetch.js: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react"; 2 | 3 | const useFetch = (url) => { 4 | const [data, setData] = useState(null); 5 | const [isPending, setIsPending] = useState(true); 6 | const [error, setError] = useState(null); 7 | 8 | useEffect(() => { 9 | // Using an AbortController to stop the fetch 10 | // when routed to another page before the fetch completes 11 | const abortController = new AbortController(); 12 | 13 | setTimeout(() => { 14 | fetch(url, { signal: abortController.signal }) 15 | .then((res) => { 16 | if (!res.ok) { 17 | throw Error("could not fetch data for the resource"); 18 | } 19 | return res.json(); 20 | }) 21 | .then((data) => { 22 | // console.log(data); 23 | setData(data); 24 | setIsPending(false); 25 | setError(null); 26 | }) 27 | .catch((err) => { 28 | if (err.name === "AbortError") { 29 | console.log("fetch aborted"); 30 | } else { 31 | setIsPending(false); 32 | setError(err.message); 33 | } 34 | }); 35 | }, 1000); 36 | 37 | return () => abortController.abort(); // Aborting before the fetch completes 38 | }, [url]); // Added url as the dependency 39 | 40 | return { data, isPending, error }; 41 | }; 42 | 43 | export default useFetch; -------------------------------------------------------------------------------- /useInputState.js: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | 3 | function useInputState(initialValue) { 4 | const [value, setValue] = useState(initialValue); 5 | const handleChange = (event) => { 6 | setValue(event.target.value); 7 | }; 8 | const resetValue = () => { 9 | setValue(''); 10 | }; 11 | return [value, handleChange, resetValue]; 12 | } 13 | 14 | export { useInputState }; 15 | -------------------------------------------------------------------------------- /useLocalStorage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Similar to useState but stores the value in local storage paired with a key 3 | * @param {string} key The key for the local storage 4 | * @param {any} initialValue Initial value to put in local storage if it's empty 5 | * @example const [name, setName] = useLocalStorage("name", "Bihan"); 6 | * @returns {[any, Function]} [value, setValue] - value will hold the current state and setValue function should be used to update the state 7 | * @author Bihan Chakraborty 8 | */ 9 | 10 | const useLocalStorage = (key, initialValue) => { 11 | const [storedValue, setStoredValue] = useState(() => { 12 | try { 13 | const value = window.localStorage.getItem(key); 14 | if (value) return JSON.parse(value); 15 | return initialValue; 16 | } catch (err) { 17 | console.log(err); 18 | return initialValue; 19 | } 20 | }); 21 | const setValue = (value) => { 22 | try { 23 | const valueToStore = value instanceof Function ? value(storedValue) : value; 24 | setStoredValue(valueToStore); 25 | window.localStorage.setItem(key, JSON.stringify(valueToStore)); 26 | } catch (err) { 27 | console.log(err); 28 | } 29 | }; 30 | return [storedValue, setValue]; 31 | }; 32 | 33 | export default useLocalStorage; 34 | -------------------------------------------------------------------------------- /usePageBottom.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | export default function usePageBottom() { 4 | const [bottom, setBottom] = React.useState(false); 5 | 6 | React.useEffect(() => { 7 | function handleScroll() { 8 | const isBottom = 9 | window.innerHeight + document.documentElement.scrollTop 10 | === document.documentElement.offsetHeight; 11 | setBottom(isButton); 12 | } 13 | window.addEventListener("scroll", handleScroll); 14 | return () => { 15 | window.removeEventListener("scroll", handleScroll); 16 | }; 17 | }, []); 18 | 19 | return bottom; 20 | } -------------------------------------------------------------------------------- /useToggleHook.js: -------------------------------------------------------------------------------- 1 | import { useCallback, useState } from 'react'; 2 | 3 | const useToggle = (initialState = false) => { 4 | const [state, setState] = useState(initialState); 5 | 6 | const toggle = useCallback(() => setState(state => !state), []); 7 | 8 | return [state, toggle] 9 | } 10 | 11 | export default useToggle; -------------------------------------------------------------------------------- /useUserStatus.js: -------------------------------------------------------------------------------- 1 | // useUserStatus: A custom react hook to detect if a user is Online or Offline. 2 | import { useState, useEffect } from 'react'; 3 | 4 | const useUserStatus = () => { 5 | const [online, setOnline] = useState(navigator.onLine); 6 | 7 | const onlineHandler = () => { 8 | setOnline(true); 9 | }; 10 | 11 | const offlineHandler = () => { 12 | setOnline(false); 13 | }; 14 | 15 | useEffect(() => { 16 | window.addEventListener('online', onlineHandler); 17 | window.addEventListener('offline', offlineHandler); 18 | }, []); 19 | 20 | return online; 21 | }; 22 | 23 | export default useUserStatus; -------------------------------------------------------------------------------- /usefulHooks.js: -------------------------------------------------------------------------------- 1 | import usePageBottom from './usePageBottom'; 2 | import { useArray } from './useArray'; 3 | import { useInputState } from './useInputState'; 4 | import useToggle from './useToggleHook'; 5 | import useUserStatus from './useUserStatus'; 6 | import useLocalStorage from './useLocalStorage'; 7 | 8 | export { usePageBottom, useToggle, useUserStatus, useInputState, useArray, useLocalStorage }; 9 | --------------------------------------------------------------------------------