{"id":23399713,"url":"https://github.com/ch0ripain/react-custom-hooks","last_synced_at":"2026-05-16T17:38:36.370Z","repository":{"id":268952682,"uuid":"905970273","full_name":"ch0ripain/react-custom-hooks","owner":"ch0ripain","description":"🧙‍♂️ Working with custom hooks 🧙‍♂️","archived":false,"fork":false,"pushed_at":"2024-12-20T02:45:59.000Z","size":4410,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-08T19:53:09.466Z","etag":null,"topics":["frontend","react","react-custom-hooks","reactjs","web-development"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ch0ripain.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-12-19T22:09:07.000Z","updated_at":"2024-12-20T02:48:13.000Z","dependencies_parsed_at":null,"dependency_job_id":"c83dbcbd-341b-483d-a849-85fdd3d74072","html_url":"https://github.com/ch0ripain/react-custom-hooks","commit_stats":null,"previous_names":["ch0ripain/react-custom-hooks"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ch0ripain/react-custom-hooks","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ch0ripain%2Freact-custom-hooks","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ch0ripain%2Freact-custom-hooks/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ch0ripain%2Freact-custom-hooks/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ch0ripain%2Freact-custom-hooks/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ch0ripain","download_url":"https://codeload.github.com/ch0ripain/react-custom-hooks/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ch0ripain%2Freact-custom-hooks/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279006455,"owners_count":26084107,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-11T02:00:06.511Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["frontend","react","react-custom-hooks","reactjs","web-development"],"created_at":"2024-12-22T10:16:14.659Z","updated_at":"2025-10-11T06:10:25.676Z","avatar_url":"https://github.com/ch0ripain.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003e🧙‍♂️ Custom Hooks 🧙‍♂️\u003c/h1\u003e\n\nA custom hook is simply a normal JS \u003ccode\u003efunction\u003c/code\u003e whose purpose is to wrap all the \u003ccode\u003estate/logic\u003c/code\u003e which is closely-related and repetitive to use it wherever you want avoiding that boilerplate code and encouraging reusability. \n\nIn this project, i used a \u003ccode\u003ecustom hook\u003c/code\u003e to group up a \u003ccode\u003efetch\u003c/code\u003e feature that manages 3 related \u003ccode\u003estates\u003c/code\u003e and some \u003ccode\u003elogic\u003c/code\u003e\n\n```javascript\n  //states\n  const [userPlaces, setUserPlaces] = useState([]);\n  const [isFetching, setIsFetching] = useState(false);\n  const [error, setError] = useState();\n  //logic\n  useEffect(() =\u003e {\n    async function fetchPlaces() {\n      setIsFetching(true);\n      try {\n        const places = await fetchUserPlaces();\n        setUserPlaces(places);\n      } catch (error) {\n        setError({ message: error.message || 'Failed to fetch user places.' });\n      }\n      setIsFetching(false);\n    }\n    fetchPlaces();\n  }, []);\n```\n\n## Creating the \u003ccode\u003eCustom Hook\u003c/code\u003e 🔧\n\nI organized the project by adding a \u003ccode\u003ehooks\u003c/code\u003e folder and a \u003ccode\u003euseFetch.js\u003c/code\u003e file. \n\n- \u003ccode\u003efolder\u003c/code\u003e ➡️ can also be named \u003ccode\u003ecustomhooks\u003c/code\u003e or anything descriptive.\n- \u003ccode\u003efile\u003c/code\u003e ➡️ name must start with \u003ccode\u003euse\u003c/code\u003e to comply and take advantage of \u003ccode\u003eReact Hooks Rules\u003c/code\u003e\n\n```javascript\nexport function useFetch(fetchFn,initialValue){\n  //modified states\n  const [isFetching, setIsFetching] = useState(false);\n  const [data, setData] = useState(initialValue);\n  const [error, setError] = useState();\n  //modified logic\n  useEffect(() =\u003e {\n    async function fetchData() {\n      setIsFetching(true);\n      try {\n        const data = await fetchFn();\n        setData(places);\n      } catch (error) {\n        setError({ message: error.message || 'Failed to fetch data.' });\n      }\n      fetchData(false);\n    }\n    fetchPlaces();\n  }, [fetchFn]);\n\n  return {\n  isFetching,\n  data,\n  setData,\n  error\n}\n```\n\n- Generalize \u003ccode\u003estate/logic\u003c/code\u003e ➡️ state and logic variables names are now more generic.\n- Flexible \u003ccode\u003eParameters\u003c/code\u003e ➡️ added \u003ccode\u003efetchFn\u003c/code\u003e and \u003ccode\u003einitialValue\u003c/code\u003e to allow dynamic usage.\n- Effect Dependencies ➡️ ensured \u003ccode\u003efetchFn\u003c/code\u003e is listed as a dependency for proper reusability.\n- Reusability ➡️ returns an \u003ccode\u003eobject\u003c/code\u003e containing all \u003ccode\u003evalues\u003c/code\u003e and \u003ccode\u003efunctions\u003c/code\u003e to expose.\n\n## Using the \u003ccode\u003eCustom Hook\u003c/code\u003e 🔄\n\nNow, this \u003ccode\u003ecustom hook\u003c/code\u003e can be used as follows:\n\n```javascript\n  import { useFetch } from \"./hooks/useFetch.js\";\n  const { isFetching, data: userPlaces, error } = useFetch(fetchUserPlaces, []);\n  ...\n  \u003cDummyComponent isLoading={isFetching} places={userPlaces} /\u003e\n  {error \u0026\u0026 \u003cError title=\"An error occurred!\" message={error.message} /\u003e}\n```\n\n## Another Use Case: Nested Logic in \u003ccode\u003eFetch\u003c/code\u003e 🎩\nIn \u003ccode\u003eAvailablePlaces.jsx\u003c/code\u003e, I needed to \u003ccode\u003efetch\u003c/code\u003e available places and sort them by user location using the \u003ccode\u003enavigator\u003c/code\u003e API:\n\n```javascript\n useEffect(() =\u003e {\n          ...\n                navigator.geolocation.getCurrentPosition((position) =\u003e {\n                const sortedPlaces = sortPlacesByDistance(\n                  places,\n                  position.coords.latitude,\n                  position.coords.longitude\n                );\n          ...\n    }\n```\n\nTo integrate this with the \u003ccode\u003ecustom hook\u003c/code\u003e, a \u003ccode\u003ecustomized fetch function\u003c/code\u003e was needed:\n```javascript\n  //create a function with all the nested behavior what is needed\n   async function fetchSortedPlaces(){\n   const places = await fetchAvailablePlaces() // first retrieve all that places\n   //then returns a Promise with the resolve (sortedPlaces) or reject (not handled in this case)\n   return new Promise((resolve,reject) =\u003e {\n   navigator.geolocation.getCurrentPosition((position) =\u003e {\n                const sortedPlaces = sortPlacesByDistance(\n                  places,\n                  position.coords.latitude,\n                  position.coords.longitude\n                );\n                resolve(sortedPlaces)\n   })\n   })\n   }\n```\nNow, use the \u003ccode\u003ecustom hook\u003c/code\u003e with the \u003ccode\u003efetch\u003c/code\u003e function\n```javascript\n const { isFetching, data: availablePlaces, error } = useFetch(fetchSortedPlaces, []);\n```\n## Quick Recap 🔄\n\n- Create a reusable \u003ccode\u003ecustom hook\u003c/code\u003e file (\u003ccode\u003euseFn.js\u003c/code\u003e) to manage some closely-related \u003ccode\u003estate/logic\u003c/code\u003e.\n- Generalize the \u003ccode\u003estate/logic\u003c/code\u003e and also add \u003ccode\u003eparameters\u003c/code\u003e for flexibility.\n- Handle other use cases with \u003ccode\u003ecustom functions\u003c/code\u003e (\u003ccode\u003easync/Promise\u003c/code\u003e).\n\nFinally, the project is cleaner and the \u003ccode\u003ecustom hook\u003c/code\u003e can be easily reused across \u003ccode\u003ecomponents\u003c/code\u003e as it is unique to each component's use.\n\n\n---\n\u003cp align=\"center\"\u003e🐸 This project is a practice exercise I learned from the \u003ca href='https://www.udemy.com/course/react-the-complete-guide-incl-redux/?couponCode=ST7MT110524'\u003eAcademind's React Course\u003c/a\u003e 🐸\u003c/p\u003e\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fch0ripain%2Freact-custom-hooks","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fch0ripain%2Freact-custom-hooks","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fch0ripain%2Freact-custom-hooks/lists"}