{"id":22337729,"url":"https://github.com/shalimov/react-hooks-combine","last_synced_at":"2025-07-29T22:33:03.471Z","repository":{"id":34871704,"uuid":"182078566","full_name":"Shalimov/react-hooks-combine","owner":"Shalimov","description":"Hooks powered, recompose like utility belt for ladies and gentlemen.","archived":false,"fork":false,"pushed_at":"2023-01-04T21:43:58.000Z","size":1698,"stargazers_count":9,"open_issues_count":12,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-11-19T15:57:20.542Z","etag":null,"topics":["api","api-wrapper","hooks","hooks-wrapper","react","reactjs","recompose","structure"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Shalimov.png","metadata":{"files":{"readme":"readme.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-04-18T11:53:23.000Z","updated_at":"2024-08-23T06:32:16.000Z","dependencies_parsed_at":"2023-01-15T10:00:43.661Z","dependency_job_id":null,"html_url":"https://github.com/Shalimov/react-hooks-combine","commit_stats":null,"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Shalimov%2Freact-hooks-combine","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Shalimov%2Freact-hooks-combine/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Shalimov%2Freact-hooks-combine/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Shalimov%2Freact-hooks-combine/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Shalimov","download_url":"https://codeload.github.com/Shalimov/react-hooks-combine/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228054452,"owners_count":17862129,"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","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":["api","api-wrapper","hooks","hooks-wrapper","react","reactjs","recompose","structure"],"created_at":"2024-12-04T06:11:10.143Z","updated_at":"2024-12-04T06:11:10.946Z","avatar_url":"https://github.com/Shalimov.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# React hooks combine\n\n[Hooks](https://reactjs.org/docs/hooks-intro.html) powered, recompose like utility belt for ladies and gentlemen.\n\n---\n\nReact Hooks Combine (RHC) is a simple utility belt to help you split up logic for your components between container (smart) part and dummy component (view) part.\nIt helps you to create only one [__HOC__](https://reactjs.org/docs/higher-order-components.html) effortlessly with [__custom hook__](https://reactjs.org/docs/hooks-custom.html) which combines all listed [HOOKS](https://reactjs.org/docs/hooks-intro.html) (all in one).\n\nIt has API Design similar to [Recompose](https://github.com/acdlite/recompose).\n\n---\n## Documentation\nDocumentation can be found here: [API Reference](/docs/api-reference.md)\n\nYou can improve it by sending pull requests to this repository.\n\n---\n## Let's Get Started\n\n__Prerequisites:__\n- [React \u003e= 16.8.0](https://reactjs.org/)\n- __[yarn](https://yarnpkg.com/ru/)__ _or_ __npm__\n\n\n__Install (choose preferable way)__\n- `yarn add react-hooks-combine`\n- `npm install react-hooks-combine`\n\n__Then...__\n\n```javascript\nimport React from 'react'\n\nimport { withState, pipe, withCallbacks } from 'react-hooks-combine'\n\nconst useCount = pipe(\n  withState('count', 'setCount', 0),\n  // try to not forget about dependencies since it's hooks, not a hocs\n  withCallbacks({\n    increment: ({ count, setCount }) =\u003e () =\u003e setCount(count + 1),\n    decrement: ({ count, setCount }) =\u003e () =\u003e setCount(count - 1),\n  })\n)\n\nfunction Counter() {\n  const { count, increment, decrement } = useCount()\n\n  return (\n    \u003cdiv\u003e\n      \u003cbutton onClick={decrement}\u003e-1\u003c/button\u003e\n      {count}\n      \u003cbutton onClick={increment}\u003e+1\u003c/button\u003e\n    \u003c/div\u003e\n  )\n}\n\nexport default Counter\n```\n\n__OR__\n\n```javascript\nimport { pipe, withAsyncEffect, withCallbacks } from 'react-hooks-combine'\n\nconst useCurrentUser = pipe(\n  withContext('repository', RepositoryContext),\n  withAsyncEffect({\n    deps: [],\n    dataName: 'details',\n    loadingName: 'loading',\n    async asyncAction({ repository } /* state */, props) {\n      const { userRepository } = repository\n      const details = await userRepository.getCurrentUser()\n      return details\n    }\n  }),\n  // check withCallbacks section for syntax\n  withCallbacks({\n    onDelete: () =\u003e () =\u003e {\n      ...\n    },\n\n    onUpdate: {\n      deps: [...],\n      func: () =\u003e () =\u003e {},\n    },\n  }, [...]),\n)\n\nexport const UserView = (props) =\u003e {\n  // useCurrentUser is a custom hook\n  // and returns object which contains properties:\n  // details, onDelete, onUpdate, loading, repository\n  // details contains info that comes from some external source by async request\n  const user = useCurrentUser(props)\n\n  return (\n    \u003cdiv\u003e\n      \u003ch2\u003eHello {user.details.firstName\u003c/h2\u003e\n      ...\n      \u003cbutton click={user.onUpdate}\u003eUpdate\u003c/button\u003e\n      \u003cbutton click={user.onDelete}\u003eDelete\u003c/button\u003e\n    \u003c/div\u003e\n  )\n}\n```\n\n__OR__\n\n```javascript\n// component.jsx\nimport React from 'react'\n\nexport const UserPageComponent = ({ loading, userData, onSubmit, onCancel }) =\u003e (\n  \u003cdiv\u003e\n    \u003ch2\u003eUser Form\u003c/h2\u003e\n    \u003cContentLoadIndicator loading={loading}\u003e\n      {\n        () =\u003e (\n          \u003cUserForm \n            initialValues={userData}\n            onSubmit={onSubmit}\n            onCancel={onCancel} /\u003e\n        )\n      }\n    \u003c/ContentLoadIndicator\u003e\n  \u003c/div\u003e\n)\n```\n\n```javascript\n// container.js (withAsyncEffect + withCallbacks)\nimport { combine, withAsyncEffect, withCallbacks } from 'react-hooks-combine'\n\nimport { UserPageComponent } from './component'\n\nexport default combine(\n  withAsyncEffect({\n    deps: ['userId'], // will request again if user id is changed\n    dataName: 'userData', // 'data' by default\n    asyncAction: (_state, ownProps) =\u003e ownProps.userService.load(ownProps.userId),\n  }),\n  withCallbacks({\n    onSubmit: (state, props) =\u003e async (formData) =\u003e {\n      const { userData } = state\n      const { userService } = props\n\n      await userService.save({ ...userData, ...formData})\n      ...\n    },\n\n    onCancel: () =\u003e () =\u003e {\n      ...\n    }\n  }, ['userData'])\n)(UserPageComponent)\n\n```\n\n__OR__\n\n```javascript\n// component.jsx\nimport React from 'react'\n\nexport const CounterComponent = ({ count, onPlus, onMinus }) =\u003e (\n  \u003cdiv\u003e\n    \u003cstrong\u003eActive: {count}\u003c/strong\u003e\n    \u003cbutton type=\"button\" onClick={onPlus}\u003e+\u003c/button\u003e\n    \u003cbutton type=\"button\" onClick={onMinus}\u003e-\u003c/button\u003e\n  \u003c/div\u003e\n)\n```\n\n```javascript\n// container.js (withReducer + withCallbacks)\nimport { combine, withReducer, withCallbacks } from 'react-hooks-combine'\n\nimport { CounterComponent } from './component'\n\nconst INC = 'INC'\nconst DEC = 'DEC'\n\nconst reducer = (count, action) =\u003e {\n    switch(action.type) {\n      case INC: return count + 1\n      case DEC: return count - 1\n      default: return count\n    }\n}\n\nexport default combine(\n  withReducer({\n    reducer,\n    stateName: counterState,\n    initialState: 0,\n  }),\n  withCallbacks({\n    onPlus: ({ counterState, dispatch }, _props) =\u003e () =\u003e {\n      dispatch({ type: INC })\n    },\n\n    onMinus: ({ counterState, dispatch }, _props) =\u003e () =\u003e {\n      dispatch({ type: DEC })\n    }\n  }, ['counterState']), // \u003c-  deps for useCallback (CHECK API TO LEARN MORE)\n)(CounterComponent)\n\n```\n__OR__\n\n```javascript\n// container.js (withState + withCallbacks)\nimport { combine, withState, withCallbacks } from 'react-hooks-combine'\n\nimport { CounterComponent } from './component'\n\nexport default combine(\n  withState('count', 'setCount', 0),\n  withCallbacks({\n    onPlus: ({ count, setCount }, _props) =\u003e () =\u003e {\n      setCount(count + 1)\n    },\n\n    onMinus: ({ setCount }, _props) =\u003e () =\u003e {\n      setCount(count =\u003e count - 1) // function could be used\n    }\n  }, ['count']), // \u003c-  deps for useCallback (CHECK API TO LEARN MORE)\n)(CounterComponent)\n```\n\n__OR WHICHEVER YOU LIKE...__\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshalimov%2Freact-hooks-combine","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshalimov%2Freact-hooks-combine","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshalimov%2Freact-hooks-combine/lists"}