Skip to content

Commit 1ec1902

Browse files
JasonHassoldLadyBluenotesatilafassina
authored
improving the derived state section to fix #489 (#539)
Co-authored-by: Sarah <gerrardsarah@gmail.com> Co-authored-by: Atila Fassina <atila@fassina.eu>
1 parent 86bdaff commit 1ec1902

File tree

1 file changed

+82
-31
lines changed

1 file changed

+82
-31
lines changed

src/routes/guides/state-management.mdx

Lines changed: 82 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ function Counter() {
121121
};
122122

123123
createEffect(() => {
124-
setDoubleCount(count() * 2); // Update doubleCount whenever count changes
124+
setDoubleCount((prev) => prev * 2); // Update doubleCount whenever count changes
125125
});
126126

127127
return (
@@ -140,6 +140,8 @@ Here, a side-effect refers to operations or updates that affect state outside of
140140
In the `Counter` component, a `createEffect` function can be used to update the `doubleCount` state whenever the `count` state changes.
141141
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.
142142

143+
View this example of [`doubleCount` in a `createEffect` in the Solid Playground example](https://playground.solidjs.com/anonymous/b05dddaa-e62a-4c56-b745-5704f3a40194).
144+
143145
<TabsCodeBlocks>
144146
<div id="First render">
145147
```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
153155
## Derived state
154156

155157
When you want to calculate new state values based on existing state values, you can use derived state.
156-
Derived state is state that is calculated from other state values.
157158
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.
158159

159-
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):
160+
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).
160161

161-
```jsx
162-
import { createSignal } from "solid-js";
162+
This approach can be used to simplify the `doubleCount` example above, where the additional signal and effect can be replaced with a derived signal:
163+
164+
```jsx del={5, 11-13} ins={15}
165+
import { createSignal } from "solid-js"
163166

164167
function Counter() {
165168
const [count, setCount] = createSignal(0);
166169
const [doubleCount, setDoubleCount] = createSignal(0);
167170

168-
// Derived signal
169-
const squaredCount = () => {
170-
return count() * count();
171-
};
172-
173171
const increment = () => {
174172
setCount((prev) => prev + 1);
175173
};
176174

177175
createEffect(() => {
178-
setDoubleCount(count() * 2); // Update doubleCount whenever count changes
176+
setDoubleCount((prev) => prev * 2); // Update doubleCount whenever count changes
179177
});
180178

179+
const doubleCount = () => count() * 2
180+
181181
return (
182182
<>
183183
<div>Current count: {count()}</div>
@@ -188,44 +188,95 @@ function Counter() {
188188
}
189189
```
190190

191-
While this approach works, it can be inefficient as the `doubleCount` signal will be re-evaluated on every render.
192-
When a function is computationally expensive, or used multiple times within a component, this can lead to performance issues.
193-
To avoid this, Solid introduced [Memos](/concepts/derived-values/memos):
191+
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.
194192

195-
```jsx
196-
import { createSignal, createEffect, createMemo } from "solid-js";
193+
The derived signal would be re-evaluated not just each time `count` is changed, but also for each use of `doubleCount()`.
194+
195+
```jsx del={10} ins={11-14, 20-21}
196+
import { createSignal } from "solid-js"
197197

198198
function Counter() {
199-
const [count, setCount] = createSignal(0);
200-
const [doubleCount, setDoubleCount] = createSignal(0);
199+
const [count, setCount] = createSignal(0)
201200

202-
// Memo
203-
const squaredCount = createMemo(() => count() * count());
201+
const increment = () => {
202+
setCount(count() + 1)
203+
}
204+
205+
const doubleCount = () => count() * 2
206+
const doubleCount = () => {
207+
console.log('doubleCount called')
208+
return count() * 2
209+
}
210+
211+
return (
212+
<>
213+
<div>Current count: {count()}</div>
214+
<div>Doubled count: {doubleCount()}</div>
215+
<div>Doubled count: {doubleCount()}</div>
216+
<div>Doubled count: {doubleCount()}</div>
217+
<button onClick={increment}>Increment</button>
218+
</>
219+
)
220+
}
221+
```
222+
223+
```shellsession title="Console output"
224+
doubleCount called
225+
doubleCount called
226+
doubleCount called
227+
```
228+
229+
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.
230+
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.
231+
232+
Using the [`createMemo`](/reference/basic-reactivity/create-memo) function, you can create a memoized value:
233+
234+
```jsx ins={15-18, 26-28} ins=", createMemo"
235+
import { createSignal, createMemo } from "solid-js"
236+
237+
function Counter() {
238+
const [count, setCount] = createSignal(0)
204239

205240
const increment = () => {
206241
setCount((prev) => prev + 1);
207242
};
208243

209244
const doubleCount = () => {
210-
return count() * 2;
211-
};
245+
console.log('doubleCount called')
246+
return count() * 2
247+
}
248+
249+
const doubleCountMemo = createMemo(() => {
250+
console.log('doubleCountMemo called')
251+
return count() * 2
252+
})
212253

213254
return (
214255
<>
256+
<div>Current count: {count()}</div>
257+
<div>Doubled count: {doubleCount()}</div>
258+
<div>Doubled count: {doubleCount()}</div>
259+
<div>Doubled count: {doubleCount()}</div>
260+
<div>Doubled count: {doubleCountMemo()}</div>
261+
<div>Doubled count: {doubleCountMemo()}</div>
262+
<div>Doubled count: {doubleCountMemo()}</div>
215263
<button onClick={increment}>Increment</button>
216-
<div>
217-
<div>Current count: {count()}</div>
218-
<div>Doubled count: {doubleCount()}</div>
219-
<div>Squared count: {squaredCount()}</div>
220-
</div>
221264
</>
222265
);
223266
}
224267
```
225268

226-
Using the [`createMemo`](/reference/basic-reactivity/create-memo) function, you can create a memoized value that is only re-evaluated when its dependencies change.
227-
This means that the value of `squaredCount` will only be re-evaluated when the value of `count` changes.
228-
This is a more efficient approach to calculating derived state, as it only re-evaluates the memoized value when necessary.
269+
```shellsession title="Console output"
270+
doubleCountMemo called
271+
doubleCount called
272+
doubleCount called
273+
doubleCount called
274+
```
275+
276+
While accessed multiple times, the `doubleCountMemo` will only re-evaluate and log once.
277+
This is different from the derived signal, `doubleCount`, which is re-evaluated for each time it is accessed.
278+
279+
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).
229280

230281
## Lifting state
231282

@@ -244,7 +295,7 @@ function App() {
244295
const squaredCount = createMemo(() => count() * count());
245296

246297
createEffect(() => {
247-
setDoubleCount(count() * 2);
298+
setDoubleCount((prev) => prev * 2);
248299
});
249300

250301
return (

0 commit comments

Comments
 (0)