{"id":21004637,"url":"https://github.com/flaque/react-mutate","last_synced_at":"2025-05-15T01:33:09.186Z","repository":{"id":57138727,"uuid":"105389331","full_name":"Flaque/react-mutate","owner":"Flaque","description":"Add extensions to a React application!","archived":false,"fork":false,"pushed_at":"2018-04-03T18:45:35.000Z","size":1423,"stargazers_count":7,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-11-06T14:46:06.275Z","etag":null,"topics":["extensions","plugins","react","react-mutations"],"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/Flaque.png","metadata":{"files":{"readme":"README.md","changelog":null,"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":"2017-09-30T17:56:52.000Z","updated_at":"2018-09-25T02:33:44.000Z","dependencies_parsed_at":"2022-09-03T10:40:44.329Z","dependency_job_id":null,"html_url":"https://github.com/Flaque/react-mutate","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Flaque%2Freact-mutate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Flaque%2Freact-mutate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Flaque%2Freact-mutate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Flaque%2Freact-mutate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Flaque","download_url":"https://codeload.github.com/Flaque/react-mutate/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225320964,"owners_count":17456109,"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":["extensions","plugins","react","react-mutations"],"created_at":"2024-11-19T08:37:17.954Z","updated_at":"2024-11-19T08:37:18.891Z","avatar_url":"https://github.com/Flaque.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://i.imgur.com/003JozN.png\" width=\"350px\" /\u003e\n\u003c/p\u003e\n\nReact Mutate is a tool that lets you swap out nodes in React's virtual DOM. The\nmain use case is to allow end-users the ability to write and add extensions\n(what we call `mutations`) to a React application.\n\n## Disclaimer\n\n**I have 0 idea if this is actually a good idea.** Take everything with a grain\nof salt. My team and I are testing this out for\n[our project, Aurora](https://github.com/tundra-code/aurora).\n\n**This is really early in development** We've really only partially tested this\nout yet, so I would probably not use it in production yet.\n\nThe API will probably change a lot. This project could be abandoned entirely.\nNorth Korea could invade France. We could discover flying pigs in a cave\nsomewhere. 🐷✈️ You never know what's gonna happen.\n\n### Double Disclaimer\n\nA lot of the recent strategies for implementing this have been heavily inspired\nby how [Hyper](https://github.com/zeit/hyper) does it's extensions (since they\nalso use HOC's as an extension strategy). Hyper is super cool and you should\nreally check it out!\n\n## Install\n\n### With yarn\n\n```sh\nyarn add @react-mutate/core @react-mutate/loader\n```\n\n### With npm\n\n```sh\nnpm install --save @react-mutate/core @react-mutate/loader\n```\n\n## Overview\n\nReact-Mutate is a series of packages that work with each other to let you do the\nfollowing:\n\n1. Allow users to create mutations (or extensions/plugins) as\n   [React HOC's](https://reactjs.org/docs/higher-order-components.html).\n2. Let them store those mutations as npm modules.\n3. Load them in and then apply them to various nodes in your React virtual DOM.\n\n### Building an extension\n\nA typical extension that your user will write can be just one code file. You\nshould name it `index.js` or you can create\n[a node project with a package.json](https://docs.npmjs.com/cli/init) and then\npoint the [main](https://docs.npmjs.com/files/package.json#main) attribute to be\nthe name of your file.\n\nYour file should export a \"mutations\" attribute that is an object where the keys\nare the components you would like to modify and the values are React HOC\nfunctions that modify their keys.\n\nFor example, here, I want to make all the `\u003cText /\u003e` in this application bold.\nSo I'll write an `index.js` file that has a `Text` function that will take in a\ncomponent and return it wrapped in bold tags.\n\n```js\n/* index.js */\nmodule.exports.mutations = {\n  Text: Component =\u003e (\n    \u003cb\u003e\n      {\" \"}\n      \u003cComponent /\u003e{\" \"}\n    \u003c/b\u003e\n  )\n};\n```\n\nThen, once I'm done, I can go and upload it to NPM with `npm publish`.\n`@react-mutate/loader` can help project owners easily install and load in npm\nprojects as mutations.\n\n### Installing user extensions\n\nNext, you'll integrate this into your app with `react-mutate`.\n\nThen, on your app, you can use `@react-mutate/loader` to install these npm\npackages for each user.\n\n```js\nimport { installMutations } from \"@react-mutate/loader\";\n\n// Installs a bunch of extensions in some folder for user data\ninstallMutations(\n  [\"some\", \"list\", \"of\", \"npm\", \"modules\"],\n  \"path/to/save/files\"\n);\n```\n\n### Loading user extensions\n\nThen later, you can load in those modules with `loadMutations` as a JSON object.\n\n```js\nimport { loadMutations } from \"@react-mutate/loader\";\n\nconst mutations = await loadMutations(\"path/to/save/files\");\n```\n\n### Integrating user extensions into React\n\nYou can wrap your app with a `\u003cMutationsProvider /\u003e` and put those mutations you\ngot from `loadMutations` in as a prop like so:\n\n```js\nimport { MutationsProvider } from \"@react-mutate/core\";\n\n/* ... Somewhere inside your root level React component **/\nrender() {\n    return (\n        \u003cMutationsProvider mutations={mutations}\u003e\n            \u003cApp/\u003e\n        \u003c/MutationsProvider\u003e\n    )\n}\n```\n\n### Specifying which items can be extended\n\nThen, inside your `App` you can specify which components you would like to be\nextendable with `mutate` like so:\n\n```js\n// Text.js\nimport { Mutate } from \"@react-mutate/core\";\n\n// Some React component\nconst Text = ({ children }) =\u003e \u003cp\u003e{children}\u003c/p\u003e;\n\nexport default mutate(Text, \"Text\");\n```\n\n### Passing in an API\n\nIf you would like to pass in some functions, you can use the third optional\nparameter of `mutate`:\n\n```js\nconst API = () =\u003e {\n  Foo: () =\u003e {\n    console.log(\"Hello I am a function\");\n  };\n};\n\nconst Text = ({ children }) =\u003e \u003cp\u003e{children}\u003c/p\u003e;\n\nexport default mutate(Text, \"Text\", API);\n```\n\n#### If you're using redux, you may not need this.\n\nWith redux, you can just pass functions via `mapDispatchToProps`, which may help\nyou give specific components access only to certain apis.\n\n```js\nimport { doFoo } from \"./actions\";\n\nconst Text = ({ children }) =\u003e \u003cp\u003e{children}\u003c/p\u003e;\n\nconst mapDispatchToProps = dispatch =\u003e {\n  return {\n    Foo: () =\u003e dispatch(doFoo)\n  };\n};\n\nexport default connect(null, mapDispatchToProps)(mutate(Text, \"Text\"));\n```\n\n## Mutations vs Extensions\n\nWe've chosen to call these `mutations` instead of `extensions` because they work\ndifferently. With React mutations, a user can write an extension for another\nextension.\n\nFor example, it's entirely possible to have an extension list that looks like\nthis:\n\n```js\nconst userExtension = {\n  Base: withAlpha,\n  WithAlpha: withBeta,\n  WithBeta: withGamma\n  // and so on...\n};\n```\n\nAlso, mutations don't need to render the existing code. Traditional JS\nextensions might just add the extension's JS directly onto the existing base,\nwhich can lead to slowdown. Mutations will render INSTEAD of the existing code.\n\n(Though it will still load in the code, so it'll still be larger and less\nefficient than no extensions)\n\nMutations also allow you to explicitly say what things are easily mutable and\nwhat things are not. This lets you clearly define your API and also\nincrementally add in extensibility to your applicaiton.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflaque%2Freact-mutate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fflaque%2Freact-mutate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflaque%2Freact-mutate/lists"}