diff --git a/src/routes/guides/state-management.mdx b/src/routes/guides/state-management.mdx index 62397245f..969d9822f 100644 --- a/src/routes/guides/state-management.mdx +++ b/src/routes/guides/state-management.mdx @@ -121,7 +121,7 @@ function Counter() { }; createEffect(() => { - setDoubleCount(count() * 2); // Update doubleCount whenever count changes + setDoubleCount((prev) => prev * 2); // Update doubleCount whenever count changes }); return ( @@ -140,6 +140,8 @@ Here, a side-effect refers to operations or updates that affect state outside of In the `Counter` component, a `createEffect` function can be used to update the `doubleCount` state whenever the `count` state changes. This keeps the `doubleCount` state in sync with the `count` state, and allows the UI to display the doubled value of `count` to the user. +View this example of [`doubleCount` in a `createEffect` in the Solid Playground example](https://playground.solidjs.com/anonymous/b05dddaa-e62a-4c56-b745-5704f3a40194). +
```html title="Counter.tsx" Current count: 0 Doubled count: 0 ``` @@ -153,31 +155,29 @@ This keeps the `doubleCount` state in sync with the `count` state, and allows th ## Derived state When you want to calculate new state values based on existing state values, you can use derived state. -Derived state is state that is calculated from other state values. This is a useful pattern when you want to display a transformation of a state value to the user, but do not want to modify the original state value or create a new state value. -Derived values can be created through using a signal within a function, which can be referred to as a [derived signal](/concepts/derived-values/derived-signals): +Derived values can be created using a signal within a function, which can be referred to as a [derived signal](/concepts/derived-values/derived-signals). -```jsx -import { createSignal } from "solid-js"; +This approach can be used to simplify the `doubleCount` example above, where the additional signal and effect can be replaced with a derived signal: + +```jsx del={5, 11-13} ins={15} +import { createSignal } from "solid-js" function Counter() { const [count, setCount] = createSignal(0); const [doubleCount, setDoubleCount] = createSignal(0); - // Derived signal - const squaredCount = () => { - return count() * count(); - }; - const increment = () => { setCount((prev) => prev + 1); }; createEffect(() => { - setDoubleCount(count() * 2); // Update doubleCount whenever count changes + setDoubleCount((prev) => prev * 2); // Update doubleCount whenever count changes }); + const doubleCount = () => count() * 2 + return ( <>
Current count: {count()}
@@ -188,44 +188,95 @@ function Counter() { } ``` -While this approach works, it can be inefficient as the `doubleCount` signal will be re-evaluated on every render. -When a function is computationally expensive, or used multiple times within a component, this can lead to performance issues. -To avoid this, Solid introduced [Memos](/concepts/derived-values/memos): +While this approach works for simple use cases, if `doubleCount` is used several times within a component or contains a computationally expensive calculation, it can lead to performance issues. -```jsx -import { createSignal, createEffect, createMemo } from "solid-js"; +The derived signal would be re-evaluated not just each time `count` is changed, but also for each use of `doubleCount()`. + +```jsx del={10} ins={11-14, 20-21} +import { createSignal } from "solid-js" function Counter() { - const [count, setCount] = createSignal(0); - const [doubleCount, setDoubleCount] = createSignal(0); + const [count, setCount] = createSignal(0) - // Memo - const squaredCount = createMemo(() => count() * count()); + const increment = () => { + setCount(count() + 1) + } + + const doubleCount = () => count() * 2 + const doubleCount = () => { + console.log('doubleCount called') + return count() * 2 + } + + return ( + <> +
Current count: {count()}
+
Doubled count: {doubleCount()}
+
Doubled count: {doubleCount()}
+
Doubled count: {doubleCount()}
+ + + ) +} +``` + +```shellsession title="Console output" +doubleCount called +doubleCount called +doubleCount called +``` + +For cases like this, you can use [Memos](/concepts/derived-values/memos) to store the value of `doubleCount`, which are also referred to as a memoized or cached value. +When using a memo, the calculation will only run **once** when the value of `count` changes and can be accessed multiple times without re-evaluating for each additional use. + +Using the [`createMemo`](/reference/basic-reactivity/create-memo) function, you can create a memoized value: + +```jsx ins={15-18, 26-28} ins=", createMemo" +import { createSignal, createMemo } from "solid-js" + +function Counter() { + const [count, setCount] = createSignal(0) const increment = () => { setCount((prev) => prev + 1); }; const doubleCount = () => { - return count() * 2; - }; + console.log('doubleCount called') + return count() * 2 + } + + const doubleCountMemo = createMemo(() => { + console.log('doubleCountMemo called') + return count() * 2 + }) return ( <> +
Current count: {count()}
+
Doubled count: {doubleCount()}
+
Doubled count: {doubleCount()}
+
Doubled count: {doubleCount()}
+
Doubled count: {doubleCountMemo()}
+
Doubled count: {doubleCountMemo()}
+
Doubled count: {doubleCountMemo()}
-
-
Current count: {count()}
-
Doubled count: {doubleCount()}
-
Squared count: {squaredCount()}
-
); } ``` -Using the [`createMemo`](/reference/basic-reactivity/create-memo) function, you can create a memoized value that is only re-evaluated when its dependencies change. -This means that the value of `squaredCount` will only be re-evaluated when the value of `count` changes. -This is a more efficient approach to calculating derived state, as it only re-evaluates the memoized value when necessary. +```shellsession title="Console output" +doubleCountMemo called +doubleCount called +doubleCount called +doubleCount called +``` + +While accessed multiple times, the `doubleCountMemo` will only re-evaluate and log once. +This is different from the derived signal, `doubleCount`, which is re-evaluated for each time it is accessed. + +View a similar [example comparing a derived signal and a memo in the Solid Playground](https://playground.solidjs.com/anonymous/288736aa-d5ba-45f7-a01f-1ac3dcb1b479). ## Lifting state @@ -244,7 +295,7 @@ function App() { const squaredCount = createMemo(() => count() * count()); createEffect(() => { - setDoubleCount(count() * 2); + setDoubleCount((prev) => prev * 2); }); return (