{"id":13653153,"url":"https://github.com/vadimdemedes/reconciled","last_synced_at":"2025-04-23T06:31:06.682Z","repository":{"id":57349271,"uuid":"201820285","full_name":"vadimdemedes/reconciled","owner":"vadimdemedes","description":"⚛️ Simple way to create a custom React renderer","archived":false,"fork":false,"pushed_at":"2022-02-07T16:01:27.000Z","size":17,"stargazers_count":223,"open_issues_count":0,"forks_count":3,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-11T03:23:18.758Z","etag":null,"topics":[],"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/vadimdemedes.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}},"created_at":"2019-08-11T22:12:51.000Z","updated_at":"2024-09-12T18:48:52.000Z","dependencies_parsed_at":"2022-08-29T18:41:18.689Z","dependency_job_id":null,"html_url":"https://github.com/vadimdemedes/reconciled","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vadimdemedes%2Freconciled","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vadimdemedes%2Freconciled/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vadimdemedes%2Freconciled/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vadimdemedes%2Freconciled/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vadimdemedes","download_url":"https://codeload.github.com/vadimdemedes/reconciled/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249068262,"owners_count":21207480,"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":[],"created_at":"2024-08-02T02:01:06.486Z","updated_at":"2025-04-23T06:31:06.635Z","avatar_url":"https://github.com/vadimdemedes.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# reconciled [![Build Status](https://github.com/vadimdemedes/reconciled/workflows/test/badge.svg)](https://github.com/vadimdemedes/reconciled/actions)\n\n\u003e Simple way to build a custom React renderer\n\n## Install\n\n```\n$ npm install reconciled\n```\n\n## Usage\n\nHere's a minimal version of `react-dom` implemented with `reconciled` without support for updates or events:\n\n```jsx\nimport reconciled from 'reconciled';\n\nconst reconciler = reconciled({\n\tcreateNode: type =\u003e document.createElement(type),\n\tcreateTextNode: text =\u003e document.createTextNode(text),\n\tsetTextNodeValue: (node, text) =\u003e (node.textContent = text),\n\tappendNode: (parentNode, childNode) =\u003e parentNode.appendChild(childNode),\n});\n\nconst app = reconciler.create(document.body);\napp.render(\u003ch1\u003eStranger Things\u003c/h1\u003e);\napp.unmount();\n```\n\n[![Edit reconciled-demo](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/dreamy-hypatia-41w3w?fontsize=14)\n\n## What is this for?\n\nReact itself doesn't require a certain environment to run. In simple terms, it only manages components and updates. Then, renderer takes representation of this component tree and displays it somewhere. For example, every React app in the browser uses [react-dom](https://github.com/facebook/react/tree/master/packages/react-dom) renderer. [react-native](https://github.com/facebook/react-native) lets you build mobile native apps with React. [Ink](https://github.com/vadimdemedes/ink) renders your React app in the terminal. There's even [react-360](https://github.com/facebook/react-360) renderer for building VR apps.\n\nCustom React renderers let you render React apps anywhere you want, as long as you can build a custom renderer for it. This is where `reconciled` comes in. There's not a lot of documentation around building custom renderers, so I extracted all my knowledge of building them for [Ink](https://github.com/vadimdemedes/ink) into a simple-to-use module. Enjoy.\n\nI think `reconciled` is a good first step in learning how to make a React renderer. If you notice that reconciled is too limited for your use case, I'd recommend checking out its source code and building your renderer without using `reconciled`.\n\n## API\n\n### reconciled(config)\n\nCreate a reconciler with the specified config for your custom renderering. Returns a [reconciler](#reconciler) object. Reconciler is a set of methods that let you synchronize React's state with your custom output (see example above).\n\n#### config\n\nType: `object`\n\nMethods for manipulating nodes.\n\n##### createNode(type, props)\n\nCreate a new node.\n\n###### type\n\nType: `string`\n\nName of the node that's being rendered. When rendering `\u003ch1\u003e`, `type` equals `'h1'`.\n\n###### props\n\nType: `object`\n\nProps to add to the node. When rendering `\u003cinput value=\"abc\"/\u003e`, `props` equals `{ value: 'abc' }`.\n\nExample implementation:\n\n```js\nconst createNode = (type, props) =\u003e {\n\tconst node = document.createElement(type);\n\n\tfor (const [key, value] of Object.entries(props)) {\n\t\tnode.setAttribute(key, value);\n\t}\n\n\treturn node;\n};\n```\n\nLearn more:\n\n- [document.createElement()](https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement)\n- [Element.setAttribute()](https://developer.mozilla.org/en-US/docs/Web/API/Element/setAttribute)\n\n##### createTextNode(text)\n\nCreate a new text node. For example, when rendering `\u003ch1\u003eHello World\u003c/h1\u003e`, a text node will be created where `text` equals `'Hello World'`.\n\n###### text\n\nType: `string`\n\nValue of text node.\n\nExample implementation:\n\n```js\nconst createTextNode = text =\u003e document.createTextNode(text);\n```\n\nLearn more:\n\n- [document.createTextNode()](https://developer.mozilla.org/en-US/docs/Web/API/Document/createTextNode)\n\n##### setTextNodeValue(node, text)\n\nUpdate value of a text node.\n\n###### node\n\nType: `any`\n\nText node to update.\n\n###### text\n\nType: `string`\n\nText to update in a text node.\n\nExample implementation:\n\n```js\nconst setTextNodeValue = (node, text) =\u003e {\n\tnode.textContent = text;\n};\n```\n\nLearn more:\n\n- [Node.textContent](https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent)\n\n##### appendNode(parentNode, childNode)\n\nInsert a new node to parent node as the last child.\n\n###### parentNode\n\nType: `any`\n\nParent node to append child node into.\n\n###### childNode\n\nType: `any`\n\nChild node to append.\n\nExample implementation:\n\n```js\nconst appendNode = (parentNode, childNode) =\u003e {\n\tparentNode.appendChild(childNode);\n};\n```\n\nLearn more:\n\n- [Node.appendChild()](https://developer.mozilla.org/en-US/docs/Web/API/Node/appendChild)\n\n##### insertBeforeNode(parentNode, newChildNode, beforeChildNode)\n\nInsert a new node before a certain child node.\n\n###### parentNode\n\nType: `any`\n\nParent node to insert child node into.\n\n###### newChildNode\n\nType: `any`\n\nNode to insert.\n\n###### beforeChildNode\n\nType: `any`\n\nNode used for reference, so that new node is inserted before this one.\n\nExample implementation:\n\n```js\nconst insertBeforeNode = (parentNode, newChildNode, beforeChildNode) =\u003e {\n\tparentNode.insertBefore(newChildNode, beforeChildNode);\n};\n```\n\nLearn more:\n\n- [Node.insertBefore()](https://developer.mozilla.org/en-US/docs/Web/API/Node/insertBefore)\n\n##### updateNode(node, oldProps, newProps)\n\nUpdate node with new props.\n\n###### node\n\nType: `any`\n\nNode to update.\n\n###### oldProps\n\nType: `object`\n\nSet of old props. Compare `newProps` to this object to figure out which props were removed.\n\n###### newProps\n\nSet of new props.\n\nExample implementation:\n\n```js\nconst updateNode = (node, oldProps, newProps) =\u003e {\n\tfor (const key of Object.keys(oldProps)) {\n\t\tif (newProps[key] === undefined) {\n\t\t\tnode.removeAttribute(key);\n\t\t}\n\t}\n\n\tfor (const [key, value] of Object.entries(newProps)) {\n\t\tnode.setAttribute(key, value);\n\t}\n};\n```\n\nLearn more:\n\n- [Element.removeAttribute()](https://developer.mozilla.org/en-US/docs/Web/API/Element/removeAttribute)\n- [Element.setAttribute()](https://developer.mozilla.org/en-US/docs/Web/API/Element/setAttribute)\n\n##### removeNode(parentNode, childNode)\n\nRemove child node from parent node.\n\n###### parentNode\n\nType: `any`\n\nParent node.\n\n###### childNode\n\nType: `any`\n\nChild node.\n\nExample implementation:\n\n```js\nconst removeNode = (parentNode, childNode) =\u003e {\n\tparentNode.removeChild(childNode);\n};\n```\n\nLearn more:\n\n- [Node.removeChild()](https://developer.mozilla.org/en-US/docs/Web/API/Node/removeChild)\n\n##### render()\n\nCallback which is called after every change is completed by the reconciler.\nUseful for renderers like [Ink](https://github.com/vadimdemedes/ink), which have to build custom output for environment that renderer is built for. In Ink's case, it's terminal, so there's no DOM like in the browser. Use this callback as an indication that there has been a change and UI needs to be updated.\n\n### reconciler\n\nType: `object`\n\n#### render(node)\n\nUpdate current node tree with a new node and its children.\n\n##### node\n\nType: `JSX.Element`\n\nNew node to replace the current one with.\n\nExample:\n\n```js\nreconciler.render(\u003ch1\u003eHello Mind Flayer\u003c/h1\u003e);\n```\n\n#### unmount()\n\nUnmount entire node tree and remove all nodes.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvadimdemedes%2Freconciled","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvadimdemedes%2Freconciled","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvadimdemedes%2Freconciled/lists"}