Skip to content

Commit 667db0c

Browse files
committed
update docs for threading & createStore functions
1 parent df3828a commit 667db0c

File tree

5 files changed

+102
-6
lines changed

5 files changed

+102
-6
lines changed

Diff for: website/docs/README.md

+2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
- [Glossary](Glossary.md)
2626
- [API Reference](api/README.md)
2727
- [createStore](api/createStore.md)
28+
- [createThreadSafeStore](api/createThreadSafeStore.md)
29+
- [createSameThreadEnforcedStore](api/createSameThreadEnforcedStore.md)
2830
- [Store](api/Store.md)
2931
- [applyMiddleware](api/applyMiddleware.md)
3032
- [compose](api/compose.md)

Diff for: website/docs/api/createSameThreadEnforcedStore.md

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
id: createSameThreadEnforcedstore
3+
title: createSameThreadEnforcedStore
4+
sidebar_label: createSameThreadEnforcedStore
5+
hide_title: true
6+
---
7+
8+
# `createSameThreadEnforcedStore(reducer, preloadedState, enhancer)
9+
10+
Creates a Redux [store](Store.md) that can only be accessed from the same thread.
11+
Any call to the store's functions called from a thread other than thread from which
12+
it was created will throw an IllegalStateException.
13+
14+
*Strongly* recommended that [`createThreadSafeStore()`](./createThreadSafeStore.md) is used unless there is
15+
good reason to do otherwise.
16+
17+
see [`createStore()`](./createStore.md) for usage.

Diff for: website/docs/api/createStore.md

+7
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@ hide_title: true
1010
Creates a Redux [store](Store.md) that holds the complete state tree of your app.
1111
There should only be a single store in your app.
1212

13+
If using `createStore` directly, it will not be threadsafe.
14+
15+
It is ***STRONGLY*** recommended that [`createThreadSafeStore()`](./createThreadSafeStore.md) is used unless there is
16+
good reason to do otherwise.
17+
18+
The rest of this doc applies to all `createStore` functions.
19+
1320
#### Arguments
1421

1522
1. `reducer` _(Reducer)_: A [reducing function](../Glossary.md#reducer) that returns the next

Diff for: website/docs/api/createThreadSafeStore.md

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
id: createThreadSafeStore
3+
title: createThreadSafeStore
4+
sidebar_label: createThreadSafeStore
5+
hide_title: true
6+
---
7+
8+
# `createThreadSafeStore(reducer, preloadedState, enhancer)
9+
10+
Creates a Redux [store](Store.md) that is may be accessed from any thread.
11+
12+
***This is the recommended way to create a store.***
13+
14+
There is some performance overhead in using `createThreadSafeStore()` due to
15+
synchronization, however it is small and mostly likely not impact UI.
16+
17+
Some quick benchmarks on an Android app have shown that:
18+
19+
1. calling `getState` was always < 1ms with or without synchronization
20+
2. `dispatch` calls to 1-3ms longer with synchronization
21+
3. During a cold launch of app differences were more dramatic. Some calls to `dispatch` took +100ms more than an store that was not synchronized.
22+
23+
see [`createStore()`](./createStore.md) for usage.

Diff for: website/docs/introduction/Threading.md

+53-6
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,71 @@ hide_title: true
77

88
# Redux on Multi-threaded Platforms
99

10+
TLDR; use [createThreadSafeStore()](../api/createThreadSafeStore.md), unless your Javascript only
11+
1012
Redux in multi-threaded environments brings additional concerns that are not present in redux
1113
for Javascript. Javascript is single threaded, so Redux.js did not have to address the issue.
1214
Android, iOS, and native do have threading, and as such attention must be paid to which threads interact with the store.
1315

14-
As of ReduxKotlin 0.3.0 there is `same thread enforcement` for the [getState](../api/store#getstate-_or_-state-property), [dispatch](../api/store#dispatchaction-any-any), [replaceReducer](../api/store#replacereducernextreducer-reducer-state-unit),
15-
and [subscribe](../api/store#subscribelistener-storesubscriber) functions on the store. This means these methods must be called from the same thread where
16+
In a multi-threaded system invalid states and race conditions can happen.
17+
For example if `getState` was called at the same time as a dispatch, the state could represent a past
18+
state. Or 2 actions dispatched concurrently could cause an invalid state.
19+
20+
**So you there are 3 options:**
21+
22+
1) Synchronize access to the store - [createThreadSafeStore()](../api/createThreadSafeStore.md)
23+
2) Only access the store from the same thread - [createSameThreadEnforcedStore()](../api/createSameThreadEnforcedStore.md)
24+
3) Live in the wild west and access store anytime, any thread and live with consequences - NOT RECOMMENDED - [createStore()](../api/createStore.md)
25+
26+
ReduxKotlin allows all these, but most cases will fall into #1.
27+
28+
Starting with ReduxKotlin 0.5.0 there is a threadsafe store which uses synchronization (AtomicFu library)
29+
to allow safe access to all the functions on the store. This is the recommended usage for 90% of use cases.
30+
31+
```kotlin
32+
val store = createThreadSafeStore(...)
33+
```
34+
35+
Who is the other 10%? If you are only targeting Javascript thread safety is not an issue, so
36+
`createStore` is the way to go. Other possible reasons could be applications that need optimal
37+
performance, however it is unlikely that the extra overhead from synchronization will be an issue.
38+
39+
## Same thread enforcement
40+
41+
Another option is `same thread enforcement`. This means these methods must be called from the same thread where
1642
the store was created. An `IllegalStateException` will be thrown if one of these are called from a
1743
different thread.
1844

19-
If this `same thread enforcement` was not in place invalid states and race conditions could happen.
20-
For example if `getState` was called at the same time as a dispatch, the state would represent a past
21-
state. Or 2 actions dispatched concurrently could cause an invalid state.
45+
46+
`Same thread enforcement` was the default behavior for ReduxKotlin 0.3.0 - 0.4.0.
2247

2348
Note that this is __SAME__ thread enforcement - not __MAIN__ thread enforcement. ReduxKotlin does not
2449
force you to use the main thread, although you can if you'd like. Most mobile applications do redux on the main
2550
thread, however it could be moved to a background thread. Using a background thread could be desirable
2651
if the reducers & middleware processing produce UI effects such as dropped frames.
2752

28-
2953
Currently `same thread enforcement` is implemented for JVM, iOS, & macOS. The other platforms
3054
have do not have the enforcement in place yet.
55+
56+
To use `same thread enforcement`:
57+
```kotlin
58+
val store = createSameThreadEnforcedStore(...)
59+
```
60+
61+
62+
***IF*** you are using vanilla `createStore()`, then you may use an different artifact,
63+
and avoid pulling in AtomicFu dependency:
64+
65+
```groovy
66+
kotlin {
67+
sourceSets {
68+
commonMain {
69+
dependencies {
70+
implementation "org.reduxkotlin:redux-kotlin:0.5.0"
71+
}
72+
}
73+
}
74+
}
75+
```
76+
**ONLY USE THE ABOVE IF YOU DO NOT WANT THREAD SAFETY**
77+

0 commit comments

Comments
 (0)