{ "id": "77242f17b32215eeee768c98", "source": "solid:signals", "type": "github-document", "title": "fine-grained-reactivity", "content": "---\ntitle: Fine-grained reactivity\nuse_cases: \u003e-\n optimizing performance, reducing re-renders, understanding solid fundamentals,\n building efficient apps, custom reactive systems\ntags:\n - reactivity\n - performance\n - signals\n - effects\n - optimization\n - fundamentals\nversion: '1.0'\ndescription: \u003e-\n Master Solid's fine-grained reactivity system for targeted UI updates, optimal\n performance, and efficient state management patterns.\n---\n\nReactivity ensures automatic responses to data changes, eliminating the need for manual updates to the user interface (UI).\nBy connecting UI elements to the underlying data, updates become automated.\nIn a fine-grained reactive system an application will now have the ability to make highly _targeted and specific_ updates.\n\nAn example of this can be seen in the contrast between Solid and [React](https://react.dev/).\nIn Solid, updates are made to the targeted attribute that needs to be changed, avoiding broader and, sometimes unnecessary, updates.\nIn contrast, React would re-execute an entire component for a change in the single attribute, which can be less efficient.\n\nBecause of the fine-grained reactive system, unnecessary recalculations are avoided.\nThrough targeting only the areas of an application that have changed the user experience becomes smoother and more optimized.\n\n**Note:** If you're new to the concept of reactivity and want to learn the basics, consider starting with our [intro to reactivity guide](/concepts/intro-to-reactivity).\n\n## Reactive primitives\n\nIn Solid's reactivity system, there are two key elements: signals and observers.\nThese core elements serve as the foundation for more specialized reactive features:\n\n- [Stores](/concepts/stores) which are [proxies](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) that create, read, and write signals under the hood.\n- [Memos](/concepts/derived-values/memos) resemble [effects](/concepts/effects) but are distinct in that they _return_ a signal and optimize computations through caching.\n They update based on the behavior of effects, but are more ideal for computational optimization.\n- [Resources](/guides/fetching-data), building on the concept of memos, convert the asynchronicity of network requests into synchronicity, where the results are embedded within a signal.\n- Render effects are a tailored type of effect that initiate immediately, specifically designed for managing the rendering process.\n\n### Understanding signals\n\n[Signals](/concepts/signals) are like mutable variables that can point to a value now and another in the future.\nThey are made up of two primary functions:\n\n- **Getter**: how to read the current value of a signal.\n- **Setter**: a way to modify or update a signal's value.\n\nIn Solid, the [`createSignal`](/reference/basic-reactivity/create-signal) function can be used to create a signal.\nThis function returns the getter and setter as a pair in a two-element array, called a tuple.\n\n```js\nimport { createSignal } from \"solid-js\";\n\nconst [count, setCount] = createSignal(1);\n\nconsole.log(count()); // prints \"1\"\n\nsetCount(0); // changes count to 0\n\nconsole.log(count()); // prints \"0\"\n```\n\nHere, `count` serves as the getter, and `setCount` functions as the setter.\n\n### Effects\n\n[Effects](/concepts/effects) are functions that are triggered when the signals they depend on point to a different value.\nThey can be thought of as automated responders where any changes in the signal's value will trigger the effect to run.\n\n```jsx\nimport { createSignal, createEffect } from \"solid-js\";\n\nconst [count, setCount] = createSignal(0);\n\ncreateEffect(() =\u003e {\n\tconsole.log(count());\n});\n```\n\nThe effect takes a function that is called whenever _any_ of the signals it relies on changes, such as `count` in this example.\n\n## Building a reactive system\n\nTo grasp the concept of reactivity, it is often helpful to construct a reactive system from scratch.\n\nThe following example will follow the observer pattern, where data entities (signals) will maintain a list of their subscribers (effects).\nThis is a way to notify subscribers whenever a signal they observe changes.\n\nHere is a basic code outline to begin:\n\n```jsx\nfunction createSignal() {}\n\nfunction createEffect() {}\n\nconst [count, setCount] = createSignal(0);\n\ncreateEffect(() =\u003e {\n\tconsole.log(\"The count is \" + count());\n});\n```\n\n## Reactive primitives\n\n### `createSignal`\n\nThe `createSignal` function performs two main tasks:\n\n1. Initialize the value (in this case, `count` is set to `0`).\n2. Return an array with two elements: the getter and setter function.\n\n```tsx\nfunction createSignal(initialValue) {\n\tlet value = initialValue;\n\n\tfunction getter() {\n\t\treturn value;\n\t}\n\n\tfunction setter(newValue) {\n\t\tvalue = newValue;\n\t}\n\n\treturn [getter, setter];\n}\n\n// ..\n```\n\nThis allows you to retrieve the current value through the getter and make any changes via the setter.\nAt this stage, reactivity is not present, however.\n\n### `createEffect`\n\n`createEffect` defines a function that immediately calls the function that is passed into it:\n\n```jsx\n// ..\n\nfunction createEffect(fn) {\n\tfn();\n}\n\n// ..\n```\n\n### Making a system reactive\n\nReactivity emerges when linking `createSignal` and `createEffect` and this happens through:\n\n1. Maintaining a reference to the current subscriber's function.\n2. Registering this function during the creation of an effect.\n3. Adding the function to a subscriber list when accessing a signal.\n4. Notifying all subscribers when the signal has updated.\n\n```jsx\nlet currentSubscriber = null;\n\nfunction createSignal(initialValue) {\n\tlet value = initialValue;\n\tconst subscribers = new Set();\n\n\tfunction getter() {\n\t\tif (currentSubscriber) {\n\t\t\tsubscribers.add(currentSubscriber);\n\t\t}\n\t\treturn value;\n\t}\n\n\tfunction setter(newValue) {\n\t\tif (value === newValue) return; // if the new value is not different, do not notify dependent effects and memos\n\t\tvalue = newValue;\n\t\tfor (const subscriber of subscribers) {\n\t\t\tsubscriber(); //\n\t\t}\n\t}\n\n\treturn [getter, setter];\n}\n\n// creating an effect\nfunction createEffect(fn) {\n\tconst previousSubscriber = currentSubscriber; // Step 1\n\tcurrentSubscriber = fn;\n\tfn();\n\tcurrentSubscriber = previousSubscriber;\n}\n\n//..\n```\n\nA variable is used to hold a reference to the current executing subscriber function.\nThis is used to determine which effects are dependent on which signals.\n\nInside `createSignal`, the initial value is stored and a [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) is used to store any subscriber functions that are dependent on the signal.\nThis function will then return two functions for the signal:\n\n- The `getter` function checks to see if the current subscriber function is being accessed and, if it is, adds it to the list of subscribers before returning the _current_ value of the signal.\n- The `setter` function evaluated the new value against the old value, notifying the dependent functions only when the signal has been updated.\n\nWhen creating the `createEffect` function, a reference to any previous subscribers is initialized to handle any possible nested effects present.\nThe current subscriber is then passed to the given function, which is run immediately.\nDuring this run, if the effect accesses any signals it is then registered as a subscriber to those signals.\nThe current subscriber, once the given function has been run, will be reset to its previous value so that, if there are any nested effects, they are operated correctly.\n\n### Validating the reactive system\n\nTo validate the system, increment the `count` value at one-second intervals:\n\n```jsx\n//..\n\nconst [count, setCount] = createSignal(0);\n\ncreateEffect(() =\u003e {\n\tconsole.log(\"The count is \" + count());\n});\n\nsetInterval(() =\u003e {\n\tsetCount(count() + 1);\n}, 1000);\n```\n\nThis will display the incremented count value on the console at one-second intervals to confirm the reactive system's functionality.\n\n## Managing lifecycles in a reactive system\n\nIn reactive systems, various elements, often referred to as \"nodes\", are interconnected.\nThese nodes can be signals, effects, or other reactive primitives.\nThey serve as the individual units that collectively make up the reactive behavior of the system.\n\nWhen a node changes, the system will re-evaluate the parts connected to that node.\nThis can result in updates, additions, or removals of these connections, which affect the overall behavior of the system.\n\nNow, consider a scenario where a condition influences the data used to calculate an output:\n\n```jsx\n// Temperature.jsx\nconsole.log(\"1. Initialize\");\nconst [temperature, setTemperature] = createSignal(72);\nconst [unit, setUnit] = createSignal(\"Fahrenheit\");\nconst [displayTemp, setDisplayTemp] = createSignal(true);\n\nconst displayTemperature = createMemo(() =\u003e {\n\tif (!displayTemp()) return \"Temperature display is off\";\n\treturn `${temperature()} degrees ${unit()}`;\n});\n\ncreateEffect(() =\u003e console.log(\"Current temperature is\", displayTemperature()));\n\nconsole.log(\"2. Turn off displayTemp\");\nsetDisplayTemp(false);\n\nconsole.log(\"3. Change unit\");\nsetUnit(\"Celsius\");\n\nconsole.log(\"4. Turn on displayTemp\");\nsetDisplayTemp(true);\n```\n\nIn this example, the `createMemo` primitive is used to cache the state of a computation.\nThis means the computation doesn't have to be re-run if its dependencies remain unchanged.\n\nThe `displayTemperature` memo has an early return condition based on the value of `displayTemp`.\nWhen `displayTemp` is false, the memo returns a message saying \"Temperature display is off,\" and as a result, `temperature` and `unit` are not tracked.\n\nIf the `unit` is changed while `displayTemp` is false, however, the effect won't trigger since none of the memo's current dependencies (`displayTemp` in this case) have changed.\n\n### Synchronous nature of effect tracking\n\nThe reactivity system described above operates synchronously.\nThis operation has implications for how effects and their dependencies are tracked.\nSpecifically, the system registers the subscriber, runs the effect function, and then unregisters the subscriber — all in a linear, synchronous sequence.\n\nConsider the following example:\n\n```jsx\ncreateEffect(() =\u003e {\n\tsetTimeout(() =\u003e {\n\t\tconsole.log(count());\n\t}, 1000);\n});\n```\n\nThe `createEffect` function in this example, initiates a `setTimeout` to delay the console log.\nBecause the system is synchronous, it doesn't wait for this operation to complete.\nBy the time the `count` getter is triggered within the `setTimeout`, the global scope no longer has a registered subscriber.\nAs a result, this `count` signal will not add the callback as a subscriber which leads to potential issues with tracking the changes to `count`.\n\n### Handling asynchronous effects\n\nWhile the basic reactivity system is synchronous, frameworks like Solid offer more advanced features to handle asynchronous scenarios.\nFor example, the `on` function provides a way to manually specify the dependencies of an effect.\nThis is particularly useful for to make sure asynchronous operations are correctly tied into the reactive system.\n\nSolid also introduces the concept of resources for managing asynchronous operations.\nResources are specialized reactive primitives that convert the asynchronicity of operations like network requests into synchronicity, embedding the results within a signal.\nThe system can then track asynchronous operations and their state, keeping the UI up-to-date when the operation completes or its' state changes.\n\nUsing resources in Solid can assist in complex scenarios when multiple asynchronous operations are involved and the completion may affect different parts of the reactive system.\nBy integrating resources into the system, you can ensure that dependencies are correctly tracked and that the UI remains consistent with the underlying asynchronous data.", "url": "https://github.com/solidjs/solid-docs/blob/HEAD/src/routes/advanced-concepts/fine-grained-reactivity.mdx", "metadata": { "path": "src/routes/advanced-concepts/fine-grained-reactivity.mdx", "repo": "solidjs/solid-docs", "repo_url": "https://github.com/solidjs/solid-docs.git", "size": 11864, "source_type": "github" }, "hash": "c192bc3b53e389ec0a63e77eeeb52cdb4896de31e11c36d0603911a201d3a9e9", "timestamp": "2026-02-23T11:43:00.186239425+01:00" }