{"id":13846811,"url":"https://github.com/themithy/react-design-patterns","last_synced_at":"2025-07-12T07:33:09.919Z","repository":{"id":38050269,"uuid":"213035881","full_name":"themithy/react-design-patterns","owner":"themithy","description":"A research project to apply the object-oriented design patterns to React.","archived":false,"fork":false,"pushed_at":"2023-05-04T20:03:24.000Z","size":27,"stargazers_count":587,"open_issues_count":1,"forks_count":65,"subscribers_count":10,"default_branch":"master","last_synced_at":"2024-11-21T21:42:26.895Z","etag":null,"topics":["react","singleton"],"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/themithy.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,"roadmap":null,"authors":null}},"created_at":"2019-10-05T16:49:41.000Z","updated_at":"2024-11-21T18:24:55.000Z","dependencies_parsed_at":"2024-01-15T20:47:29.933Z","dependency_job_id":"dde36548-475c-45f6-8130-8063ee23f5b6","html_url":"https://github.com/themithy/react-design-patterns","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/themithy/react-design-patterns","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/themithy%2Freact-design-patterns","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/themithy%2Freact-design-patterns/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/themithy%2Freact-design-patterns/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/themithy%2Freact-design-patterns/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/themithy","download_url":"https://codeload.github.com/themithy/react-design-patterns/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/themithy%2Freact-design-patterns/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264958194,"owners_count":23689010,"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":["react","singleton"],"created_at":"2024-08-04T18:00:48.137Z","updated_at":"2025-07-12T07:33:09.561Z","avatar_url":"https://github.com/themithy.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# React software design patterns\n\nThis page describes the effort to explore the well-known software design\npatterns (e.g. singleton, adapter) in terms of React programming, whether\nimplementing them using React semantics produces any viable outcome and \nbrings any improvement is terms of code quality.\n\n## Singleton\n\nThe *singleton* pattern seems to be the perfect starter, in terms that it is\neasy to understand and has a well-foreseeable outcome in React. It also seems\nto make sense in virtually every programming paradigm. A function that can be\ncalled many times but is invoked only once is also a kind of singleton.\n\nThe implementation of this pattern can vary from simple effect (like attaching\nonly one a DOM listener) to a general HOC. However the basic idea is as\nfollows:\n\n```js\nconst Singleton = () =\u003e {\n\n  React.useEffect(() =\u003e {\n    // do some action if ref count is 0.\n\n    Singleton.refCount++\n\n    () =\u003e {\n      // destroy singleton if unmounting last reference.\n\n      Singleton.refCount--\n    }\n  })\n\n  return null\n}\n\nSingleton.refCount = 0\n```\n\nThe fundamental idea (as in every other programming language) is to keep a\n*static* property that contains the reference to the created object. Here in\nthe pseudo-code we also track the reference count, so that the singleton object\ncan be destroyed after the last reference is unmounted, but it does not have\nto.\n\nIn the example code we create a whole React sub-tree, so that the state of the \nsingleton component is persisted, even if the first reference unmounts.\n\nThe final outcome can go well-beyond having just a one component in vdom, we\ncan handle *props* update in any reference or have event callbacks behave in\nsimilar way to generic listeners.\n\nPlease see an example in the code.\n\n## Decoupling\n\n[Full article on dependency injection](doc/dependency-injection.md)\n\nThe idea of decoupling or *loose coupling* exists behind many of the design\npatterns. Is it not only the business logic or logic in general that can be\nabstracted, but virtually every concept like algorithm, state, etc.; and this\nlist is open-ended.\n\nLet us start with a very simple example below.\n\n```js\nconst text = \u003cText color=\"paleBlue\" /\u003e\n```\n\nThe implementation of the `Text` class in not exactly right, because every time\na new color is added to the palette, we need to changed the class. A much\nbetter solution would be to define the color outside, and pass it to the\ninstance of that class. This is what is called **dependency injection**.\n\n```js\nimport { paleBlue } from 'colors'\n\nconst text = \u003cText color={paleBlue} /\u003e\n```\n\n## Bridge\n\n[Full article on bridge pattern](doc/bridge-pattern.md)\n\nNow let us consider a pattern very useful in front-end projects. A component\nthat seems very simple to implement but usually turns the opposite is the\nbutton component. It starts with some border radius and primary and secondary\ncolor palette. However in the life-time of the project several features are\nrequested that make this component bloated or split in two with not obvious\nreason.  This includes:\n* the color palette going well beyound primary and secondary.\n* the necessity to display a icon on button.\n* a link that should look like a button.\n\nThis is where the *bridge pattern* comes in play, as it decouples the\nabstraction (how the component works) from the implementation (how the\ncomponent looks like).\n\n```js\nimport { Button, Link } from 'abstraction'\nimport { ButtonUI, ButtonWithIconUI } from 'implementation'\n\n\u003cButton\n  {...buttonProps} \n  uiComponent={ButtonWithIconUI}\n  uiProps={...}\n/\u003e\n\n\u003cLink\n  {...linkProps} \n  uiComponent={ButtonUI}\n  uiProps={...}\n/\u003e\n```\n\nPlease see an example in the code.\n\n## Factory\n\n[Full article on factory pattern](doc/factory-pattern.md)\n\nThe *factory pattern* allows to factor out the process of object creation.\nThis can have multiple purpose:\n* the final object depends on the parameters.\n* separate a simple object representation from the logic of creating it.\n\nThis seems especially useful in front-end programming to initialize ui\ncomponents from REST data.\n\n```js\nfunction factory(params) {\n  let condition, prop\n  \n  // do some computation with params\n\n  if (condition) {\n    return \u003cObject1 prop={prop} /\u003e\n  }\n  else {\n    return \u003cObject2 prop={prop} /\u003e\n  }\n}\n```\n\nA data to initialize a specific object can come from multiple sources (e.g.\nREST endpoints), this is an example where *abstract factory* comes into play.\nWe define multiple factories, each per endpoint, which create the same object\nbased on different data.\n\n## Builder\n\nIn the *builder pattern* the construction of an object, or even a composite,\nis done in multiple steps, for example while chunks of data arrive. It should\nthe `toElement` function to return the final element.\n\n\n```\nclass Builder {\n\n  buildStep1() { ... }\n\n  buildStep2() { ... }\n\n  toElement() {\n    return \u003cElement {...someProps} /\u003e\n  }\n}\n```\n\n## Mediator\n\n[Full article on mediator pattern](doc/mediator-pattern.md)\n\nThe *mediator pattern* allows two or more object to communicate without any of\nthis object depending on the other. This pattern is rarely seen in React\nprogramming because the communication is usually handled by third-party\nlibraries or state containers, most notably *Redux*. This is not exactly right\nfor two simple reasons:\n* A global state does not encapsulate the internals of the interaction.\n* A global state is not well-suited for storing promises and functions.\n\n```js\nconst mediator = new Mediator()\n\nconst Client = () =\u003e {\n  return (\n    \u003cReact.Fragment\u003e\n      \u003cObject1 mediator={mediator} /\u003e\n      \u003cObject2 mediator={mediator} /\u003e\n    \u003c/React.Fragment\u003e\n  )\n}\n```\n\nPlease see an example in the code.\n\n## Observer\n\nThis one is what I would call an *intuitive* design pattern and is heavily used\nin the wild.\n\n```js\nconst Observer = () =\u003e {\n  React.useEffect(() =\u003e {\n    const someFunction = () =\u003e {}\n\n    document.addEventListener('click', someFunction)\n\n    return () =\u003e {\n      document.removeEventListener('click', someFunction)\n    }\n  }, [])\n}\n```\n\n## Messaging\n\n[Full article on messaging pattern](doc/messaging-pattern.md)\n\n## Decorator\n\nThe *decorator pattern* allows to \"wrap\" object in each other, providing that\nthey share the same interface and call each other methods. In React we are\nconcerned with only one method, namely the \"render\".\n\nThe implementation may differ, in class-based components the \"HOC pattern\" can\nbe seen as an utilisation of the decorator pattern. However it gets more\ninteresting when we get to function-based components. We can just wrap\nfunctions with hooks in each other, obtaining the desired behaviour. There is\nno need to call `React.createElement`, we can just call the component is if it\nwere an ordinary function, thus saving on levels in virtual DOM.\n\n```js\n\nconst Counter = ({ count }) =\u003e {\n  return \u003cspan\u003eCount equals {count}\u003c/span\u003e\n}\n\nconst MultiplyCountDecorator = (counter) =\u003e {\n  return ({ count, ...props }) =\u003e {\n    return counter({ count: 2 * count, ...props })\n  }\n}\n\nconst DecoratedCounter = MultiplyCountDecorator(Counter)\n\n```\n\n`React.memo` is another example of a usage of the decorator pattern.\n\n## Strategy\n\n[Full article on strategy pattern](doc/strategy-pattern.md)\n\n## Facade\n\nThis is also heavily used:\n\n```js\nconst Facade = ({ generalProp }) =\u003e {\n  return (\n    \u003cReact.Fragment\u003e\n      \u003cObject1 /\u003e\n      \u003cObject2 specificProp={generalProp} /\u003e\n      \u003cObject3 /\u003e\n    \u003c/React.Fragment\u003e\n  )\n}\n```\n\n## Memento\n\nThe internal state of the component can encapsulated and referenced using\nthe *forward ref* mechanism.\n\n```js\nReact.useImperativeHandle(ref, () =\u003e ({\n  createMemento: () =\u003e { return state },\n  restore: (memento) =\u003e { setState(memento) },\n}))\n```\n\n## State\n\n[Full article on state pattern](doc/state-pattern.md)\n\n## Command\n\nThe *command pattern* is an excellent example of the general rule of design\npatterns that is to encapsulate some behaviour.\n\nIn the following example the Wizard component will encapsulate the way the user\nmoves between corresponding steps. Any change in this logic (like for example\nadding the possibility to move backward) will not affect the implementation\nof particular steps.\n\nWhen the command pattern is not used the logic of moving between steps (e.g.\nvia routing) is usually distributed among different components. Futher more\nthe accumulated state is not properly encapsulated but exposed in a global\nstate container like \"redux\".\n\n```js\n\u003cWizard\n  steps={[\n    Step1,\n    Step2,\n    Step3,\n  ]}\n/\u003e\n```\n\n## Poll\n\n[Full article on poll pattern](doc/poll-pattern.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthemithy%2Freact-design-patterns","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthemithy%2Freact-design-patterns","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthemithy%2Freact-design-patterns/lists"}