{"id":24329815,"url":"https://github.com/jim3692/lightning-function-components","last_synced_at":"2026-04-18T23:04:15.064Z","repository":{"id":205579866,"uuid":"714368894","full_name":"jim3692/lightning-function-components","owner":"jim3692","description":"Lightning Web Components but React-style","archived":false,"fork":false,"pushed_at":"2023-11-08T22:56:38.000Z","size":662,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-01-18T00:17:43.154Z","etag":null,"topics":["lightning-web-components","lwc","salesforce"],"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/jim3692.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":"2023-11-04T17:46:59.000Z","updated_at":"2023-11-11T15:20:43.000Z","dependencies_parsed_at":"2023-11-08T23:39:54.631Z","dependency_job_id":null,"html_url":"https://github.com/jim3692/lightning-function-components","commit_stats":null,"previous_names":["jim3692/lightning-function-components"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jim3692%2Flightning-function-components","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jim3692%2Flightning-function-components/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jim3692%2Flightning-function-components/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jim3692%2Flightning-function-components/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jim3692","download_url":"https://codeload.github.com/jim3692/lightning-function-components/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243012687,"owners_count":20221605,"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":["lightning-web-components","lwc","salesforce"],"created_at":"2025-01-18T00:17:51.667Z","updated_at":"2025-12-12T08:07:35.269Z","avatar_url":"https://github.com/jim3692.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Lightning Function Components\n\n\u003e Why shouldn't we have the React Function Components hooks syntax in LWC?\n\nThis project is an attempt to port some existing and implement some new LWC specific hooks inside LWC.\n\nThere has been a [draft](https://rfcs.lwc.dev/rfcs/lwc/0000-functional-components) for functional components in LWC, but it has been rejected, so I just tried to implement my own version as a library.\n\n## Considerations\n\n- Not properly tested yet, so expect bugs.\n- It overrides some LWC lifecycle hooks, so it is currently not advised to use them. Currently these lifecycle hooks are in use:\n    - `render`\n    - `renderedCallback`\n    - `disconnectedCallback`\n- The function component runs on `render`.\n- It is possible to return a different template from the function component, like in a normal `render` method.\n\n## Installation\n\n- Copy the `lightningFunctionComponent` directory to your project's `lwc` directory and deploy.\n\n## Example\n\nThe following example displays a counter that increments every second.\n\n- myComponent.js\n```js\nimport { LightningElement } from \"lwc\";\nimport { LightningFunctionComponentMixin } from \"c/lightningFunctionComponent\";\n\n// Have the FC in a separate file for cleaner code\nimport component from \"./component\";\n\n// Pass the LightningElement and our FC to the mixin\nexport default class MyComponent\n  extends LightningFunctionComponentMixin(LightningElement, component) {\n// Component body\n// Probably only useful for `@api` fields\n//   and native wire adapters, like `getRecord`\n}\n```\n\n- myComponent.html\n```html\n\u003ctemplate\u003e\n  \u003c!-- Read the label text --\u003e\n  \u003cp\u003e{state.label}\u003c/p\u003e\n\u003c/template\u003e\n```\n\n- component.js\n```js\nimport {\n  useState, // React-like useState\n  useEffect, // React-like useEffect\n  useLwcState, // Custom hook to expose data to the template\n} from \"c/lightningFunctionComponent\";\n\nconst INITIAL_LABEL = \"counter\";\n\nexport default function () {\n  // Declare the label state\n  const [label, setLabel] = useState(\"\");\n  // Declare the counter state\n  const [counter, setCounter] = useState(0);\n\n  // Expose the label to the template\n  useLwcState({ label });\n\n  useEffect(() =\u003e {\n    // On first render create the loop that increments the counter\n    const loop = setInterval(() =\u003e {\n      setCounter((old) =\u003e old + 1);\n    }, 1000);\n\n    // Clear the interval on disconnectedCallback\n    return () =\u003e {\n      clearInterval(loop);\n      console.log(\"cleared loop\", loop);\n    };\n  }, []);\n\n  useEffect(() =\u003e {\n    // Update the label on counter update\n    setLabel(`${INITIAL_LABEL} - ${counter}`);\n  }, [counter]);\n}\n```\n\n## Documentation\n\n### useApex\n\n###### Example\n\n```js\nimport getAccount from \"@salesforce/apex/MyAuraEnabledClass.getAccount\";\nimport { useApex } from \"c/lightningFunctionComponent\";\n// ...\nconst account = useApex(getAccount, accountConfig);\n```\n\n###### Details\n\nA new-custom hook that is similar to how an Apex method would be wired.\n\nParameters:\n- `adapter`: The imported Apex function.\n- `config`: The object containing for the Apex method.\n\nReturns:\n- An object containing `data` and `error`.\n\nBehavior:\n- It fetches the data on first run, and every time the `config` gets updated.\n- It's advisable to cache the `config` inside a state, or outside the FC to prevent this hook from fetching on every render.\n\n### useEffect\n\n###### Example\n\n```js\nimport { useEffect } from \"c/lightningFunctionComponent\";\n// ...\nuseEffect(() =\u003e {\n    console.log(counter);\n}, [counter]);\n```\n\n###### Details\n\nIt should work like React's useEffect.\n\nParameters:\n- `callback`: The function to call.\n- `dependencies`: An array containing the watched states.\n\nBehavior:\n- It always runs on the first render.\n- The `callback` is updated on every run, to use the latest values of the states.\n- If the `dependencies` array is not provided, then it re-runs the `callback` on every render.\n- If the `dependencies` array is empty, then it does not run again.\n- If the `dependencies` array is not empty, then it re-runs the `callback` every time a dependency updates.\n- If the `callback` returns a function, it is called before every re-run and on `disconnectedCallback`.\n\n### useEvent\n\n###### Example\n\n```html\n\u003cbutton events-click=\"handleClick\"\u003eClick me\u003c/button\u003e\n```\n\n```js\nimport { useEvent, useRef, useState } from \"c/lightningFunctionComponent\";\n// ...\nconst [name, setName] = useState('Jack');\nconst nameRef = useRef(name);\nnameRef.current = name;\n\nuseEvent('handleClick', (event) =\u003e {\n    console.log('Hello ' + nameRef.current);\n});\n```\n\n###### Details\n\nThis is a draft for handling events inside the FC. We may need [LWC#3618](https://github.com/salesforce/lwc/issues/3618) to be resolved, in order to implement a better solution.\n\nParameters:\n- `handlerName`: The name of the handler defined in the `event-*` attribute in HTML\n- `handler`: The function to be called.\n\nBehavior:\n- On every render it scans the component for elements with a `events-[name]` attribute. The `name` should be the event without the \"on\" prefix. For example, `click` instead of `onclick`.\n- When the desired event occurs, it runs the `handler` function.\n- The `handler` function is not updated after the first render, so it may end up having stale state references. It is advisable to use `useRef` to access the desired state from the `handler`, like in the example.\n\n### useLwcState\n\n###### Example\n\n```html\n\u003cp\u003e{state.name}\u003c/p\u003e\n```\n\n```js\nimport { useLwcState, useState } from \"c/lightningFunctionComponent\";\n// ...\nconst [name, setName] = useState('Jack');\nuseLwcState({ name });\n```\n\n###### Details\n\nA new-custom hook that exposes the desired states to the template, under the `state` field.\n\nParameters:\n- `state`: The new value of the `state` field of the component.\n\nBehavior:\n- On each render it checks if any of the fields, and their values, passed have been updated, and if they are different it updates the component's `state`.\n- Since the hook contains an object, and it's called at the top level of the function's body, this object is actually a new one on each render.\n\n### useRef\n\n###### Example\n\n```js\nimport { useRef } from \"c/lightningFunctionComponent\";\n// ...\nconst statusRef = useRef(status);\n// ...\nconsole.log(statusRef.current);\n```\n\n###### Details\n\nIt should work like React's useEffect.\n\nParameters:\n- `initialValue`: The value of the `current` field after the first run.\n\nReturns:\n- An object containing a `current` field.\n\nBehavior:\n- On first run, it creates a new object, containing the `current` field, set to `initialValue`.\n- On every render, it returns the same object reference, that was initially created.\n- It is typically used to cache values, or expose them to other objects/functions, without risking having stale values.\n- In React, updating the `current` field should not cause the component to re-render, however, in LWC, it may cause a re-render, as LWC no longer requires the `@track` decorator for tracked fields.\n\n### useState\n\n###### Example\n\n```js\nimport { useState } from \"c/lightningFunctionComponent\";\n// ...\nconst [name, setName] = useRef('Jack');\n// ...\nconsole.log(name);\n//...\nsetName('Chris');\n```\n\n###### Details\n\nIt should work like React's useState.\n\nParameters:\n- `initialValue`: The value of the state after the first run.\n\nReturns:\n- An array with `state` and `setState`.\n- These fields can be renamed with destructuring.\n- The `state` contains the value, that was set in the previous render, or the `initialValue`.\n- The `setState` is function used to update the `state` value.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjim3692%2Flightning-function-components","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjim3692%2Flightning-function-components","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjim3692%2Flightning-function-components/lists"}