{"id":22123491,"url":"https://github.com/proai/extended-components","last_synced_at":"2025-03-24T07:29:31.926Z","repository":{"id":94743831,"uuid":"127818623","full_name":"ProAI/extended-components","owner":"ProAI","description":":star2: React.js functional components with default props, advanced local state and lifecycle hooks","archived":false,"fork":false,"pushed_at":"2019-03-27T18:24:47.000Z","size":110,"stargazers_count":1,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-03T03:34:35.004Z","etag":null,"topics":["higher-order-component","hoc","lifecycle","react","state"],"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/ProAI.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2018-04-02T22:16:59.000Z","updated_at":"2019-03-27T18:24:48.000Z","dependencies_parsed_at":"2023-07-05T19:15:14.012Z","dependency_job_id":null,"html_url":"https://github.com/ProAI/extended-components","commit_stats":{"total_commits":13,"total_committers":1,"mean_commits":13.0,"dds":0.0,"last_synced_commit":"921e708131bfd1d3029be569b091daa62d440768"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ProAI%2Fextended-components","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ProAI%2Fextended-components/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ProAI%2Fextended-components/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ProAI%2Fextended-components/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ProAI","download_url":"https://codeload.github.com/ProAI/extended-components/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245227049,"owners_count":20580795,"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":["higher-order-component","hoc","lifecycle","react","state"],"created_at":"2024-12-01T15:33:52.882Z","updated_at":"2025-03-24T07:29:31.901Z","avatar_url":"https://github.com/ProAI.png","language":"JavaScript","readme":"_⚠️ As of React 16.8 it is recommended to use [hooks](https://reactjs.org/docs/hooks-intro.html) instead of this package._\n\n# Extended Components\n\nExtend functional React.js components with default props, advanced local state (presets for common use cases like toggle, counter, ...) and lifecycle hooks.\n\n_This package is not meant as a replacement for state management libraries like [Redux](https://github.com/reactjs/redux), it should be used for local state only (i.e. state that is used by not really more than one component)._\n\n## Problem\n\nThere are two problems that motivated me to create this package:\n\n1.  Functional components don't support local state and lifecycle hooks.\n2.  There were no presets for common local state use cases (toggles, counters, ...).\n\n## Solution\n\nThis package consists of some higher order components (HOC), which let you define default props, state and lifecycle methods for a functional component. Also you can define state presets like `useCounterState` or `useToggleState` that can be used with the `withState` HOC perfectly. If you define state, `extended-components` will pass a second argument to your functional component ([as described by Andrew Clark](https://twitter.com/acdlite/status/971598256454098944)).\n\nThis package uses HOCs and not render props. Don't get me wrong, I use render props a lot, but I think in this case HOCs have slightly advantages like a good separation of concerns and [clean code](https://twitter.com/acdlite/status/971605795501613056).\n\nTechnically `extended-components` makes use of [component squashing](https://twitter.com/acdlite/status/739918904110112770), so the original functional component will be squashed by the HOCs to improve performance.\n\n## Installation\n\n```shell\nnpm install extended-components\n# or\nyarn add extended-components\n```\n\n## Usage\n\n```jsx\nimport React from 'react';\nimport { compose, withState, lifecycle, pure } from 'extended-components';\nimport useCounterState from './useCounterState';\n\nconst enhance = compose(\n  // Use state helpers to define state\n  withState({\n    counter: useCounterState(),\n  }),\n  // Use React.js lifecycle hooks with props and state\n  lifecycle((props, { counter }) =\u003e {\n    componentDidUpdate() {\n      counter.increment();\n    },\n  }),\n  // Component is a pure component\n  pure(),\n});\n\n// Use defined state\nfunction Component(props, state) {\n  const { counter } = state;\n\n  return (\n    \u003cdiv\u003e\n      \u003cp\u003eThis component was updated {counter.count} times.\u003c/p\u003e\n      \u003cp\u003e\n        \u003cbutton onClick={() =\u003e { counter.reset() }}\u003eReset counter\u003c/button\u003e\n      \u003c/p\u003e\n    \u003c/div\u003e\n  );\n}\n\nexport default enhance(Component);\n```\n\nHint: You can use the HOCs of `extended-components` in conjunction with other higher order components, but thus these higher order components don't expect a functional component with two arguments, HOCs of `extended-components` should always be placed last, e.g.:\n\n```javascript\nconst enhance = compose(\n  withRouter(...),\n  connect(...),\n  graphql(...),\n  mapProps(...),\n  // Use extended-components HOCs last\n  withState(...),\n);\n```\n\n### Create state helpers\n\nThe purpose of this package is to enable a convient way to define state for specific use cases, but not to implement all these use cases. So it is up to you to define state helpers. A state helper is simply an object with the keys `initial` (for initial state) and `mutators` (for state mutator functions):\n\n```javascript\nfunction useCounterState() {\n  return {\n    initial: {\n      count: 0,\n    },\n    mutators: setState =\u003e ({\n      increment: () =\u003e {\n        setState(({ count }) =\u003e ({ count: count + 1 }));\n      },\n      decrement: () =\u003e {\n        setState(({ count }) =\u003e ({ count: count - 1 }));\n      },\n      reset: () =\u003e {\n        setState({ count: 0 });\n      },\n    }),\n  };\n}\n```\n\nThen you can reuse this state helper over and over like shown in the example above. For more examples have a look at the [`examples`](https://github.com/ProAI/extended-components/tree/master/examples) folder.\n\n## Docs\n\n### `defaultProps`\n\nDefines the default props of a component.\n\n```typescript\ntype DefaultProps = ((defaultProps: $Shape\u003cProps\u003e) =\u003e void) =\u003e HOC\n```\n\n### `getDerivedStateFromProps`\n\nDefines the static lifecycle hook `getDerivedStateFromProps` (introduced in React 16.3). Notice that this hook returns void (in comparison to the original hook, which returns a state object), because you can update the state via the state mutators.\n\n```typescript\ntype GetDerivedStateFromProps = ((nextProps: Props, prevState?: State) =\u003e void) =\u003e HOC\n```\n\n### `lifecycle`\n\nDefines lifecycle hooks.\n\n```typescript\ntype Lifecycle = (\n    (\n      props: Props,\n      state?: State,\n    ) =\u003e {\n      componentDidMount?: () =\u003e void,\n      shouldComponentUpdate?: (nextProps: Props, nextState?: State) =\u003e boolean,\n      componentDidUpdate?: (prevProps: Props, prevState?: State) =\u003e void,\n      componentWillUnmount?: () =\u003e void,\n    },\n  ) =\u003e HOC;\n```\n\n### `pure`\n\nEquivalent to `React.PureComponent`, but instead of a basic shallow state comparison this function makes a shallow comparison for the state of every state helper.\n\n```typescript\ntype Pure = () =\u003e HOC;\n```\n\n### `withState`\n\nDefines state with state helpers.\n\n```typescript\ntype WithState = ({\n    [string]: StateHelper\u003cSubStateValues, SubStateMutators, Props\u003e,\n  }) =\u003e HOC;\n```\n\n### `statics`\n\nDefines static properties of a component.\n\n```typescript\ntype Statics = Object =\u003e HOC;\n```\n\n### State helpers\n\nAs stated above you can define your own state helpers that should be of the following type:\n\n```typescript\ntype SetState\u003cSubStateValues, Props\u003e = (\n  $Shape\u003cSubStateValues\u003e | ((SubStateValues, Props) =\u003e $Shape\u003cSubStateValues\u003e),\n) =\u003e void;\n\ntype StateHelper\u003cSubStateValues, SubStateMutators, Props\u003e = {\n  initial: SubStateValues,\n  mutators: (SetState\u003cSubStateValues, Props\u003e) =\u003e SubStateMutators,\n};\n```\n\n_The definitions above might differ from the real Flow definitions, because the definitions in this section should just demonstrate what you can do with this package._\n\n## Flow support\n\nFor more information about the usage with Flow see [Flow support](docs/Flow%20support.md).\n\n## Inspiration\n\nThis package is heavily inspired by Andrew Clark's great library [`recompose`](https://github.com/acdlite/recompose). And I think you can perfectly use `recompose` and `extended-components` together, because `extended-components` just mimics all class features and `recompose` offers a lot more utils. You can use `extended-components` for state and lifecycle hooks and `recompose` for props manipulation and more.\n\n## Future\n\nCurrently there are only two arguments that are passed to a functional component, but you can think of more arguments. So it might be that someday this package will offer an api for higher order components like `withTheme`, `withIntl`, `withRouter` and so on, which add more arguments to the component. Each argument for a specific use case.\n\n## License\n\nThis package is released under the [MIT License](LICENSE).\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fproai%2Fextended-components","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fproai%2Fextended-components","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fproai%2Fextended-components/lists"}