Skip to content

Commit 6e95fb0

Browse files
phryneasmarkeriksonmsutkowskidouglas-treadwell
authored
upcoming: RTK 1.5.0 (#813)
Co-authored-by: Lenz Weber <[email protected]> Co-authored-by: Mark Erikson <[email protected]> Co-authored-by: Matt Sutkowski <[email protected]> Co-authored-by: Douglas Treadwell <[email protected]>
1 parent 8e8b115 commit 6e95fb0

40 files changed

+2426
-286
lines changed

.github/workflows/tests.yml

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
name: CI
2+
on: [push, pull_request]
3+
jobs:
4+
build:
5+
name: Lint, Test, Build & Pack on Node ${{ matrix.node }}
6+
7+
runs-on: ubuntu-latest
8+
strategy:
9+
matrix:
10+
node: ['12.x']
11+
12+
steps:
13+
- name: Checkout repo
14+
uses: actions/checkout@v2
15+
16+
- name: Use node ${{ matrix.node }}
17+
uses: actions/setup-node@v1
18+
with:
19+
node-version: ${{ matrix.node }}
20+
21+
- uses: c-hive/gha-npm-cache@v1
22+
23+
- name: Install deps
24+
run: npm ci --ignore-scripts
25+
26+
- name: Pack (including Prepare)
27+
run: npm pack
28+
29+
- uses: actions/upload-artifact@v2
30+
with:
31+
name: package
32+
path: reduxjs-toolkit*.tgz
33+
34+
test:
35+
name: Test Types with TypeScript ${{ matrix.ts }}
36+
37+
needs: [build]
38+
runs-on: ubuntu-latest
39+
strategy:
40+
fail-fast: false
41+
matrix:
42+
node: ['12.x']
43+
ts: ['3.5', '3.6', '3.7', '3.8', '3.9', '4.0', '4.1', 'next']
44+
steps:
45+
- name: Checkout repo
46+
uses: actions/checkout@v2
47+
48+
- name: Use node ${{ matrix.node }}
49+
uses: actions/setup-node@v1
50+
with:
51+
node-version: ${{ matrix.node }}
52+
53+
- uses: c-hive/gha-npm-cache@v1
54+
55+
- name: Install deps
56+
run: npm ci --ignore-scripts
57+
58+
- name: Install TypeScript ${{ matrix.ts }}
59+
run: npm install typescript@${{ matrix.ts }} --ignore-scripts
60+
61+
- uses: actions/download-artifact@v2
62+
with:
63+
name: package
64+
65+
- name: Unpack build artifact to dist
66+
run: tar -xzvf reduxjs-toolkit-1.4.0.tgz --strip-components=1 package/dist
67+
68+
- name: Remap @redux/toolkit from src to dist
69+
run: |
70+
sed -i -e 's|@reduxjs/toolkit": \["./src"\]|@reduxjs/toolkit": ["."]|' ./type-tests/files/tsconfig.json
71+
72+
- name: Prefix `freeze` re-export for pre-3.7 TS versions with @ts-ignore
73+
if: ${{ matrix.ts < 3.7 }}
74+
run: |
75+
sed -i -e "/import .* freeze .* from 'immer'/s/^/\/\/ @ts-ignore\n/" dist/typings.d.ts
76+
sed -i -e "/export .* freeze .* from 'immer'/s/^/\/\/ @ts-ignore\n/" src/index.ts
77+
78+
- name: Use typings-tester for old TS versions
79+
if: ${{ matrix.ts < 3.9 }}
80+
run: |
81+
sed -i -e 's/"cd type-tests.*"/"npm run test type-tests"/' package.json
82+
sed -i -e 's/@ts-expect-error/typings:expect-error/' type-tests/files/*.typetest.ts
83+
sed -i -e 's/@ts-expect-error/@ts-ignore/' type-tests/files/*.ts
84+
mv type-tests/types.test.disabled.ts type-tests/types.test.ts
85+
86+
- name: Test types
87+
run: |
88+
./node_modules/.bin/tsc --version
89+
npm run type-tests

.travis.yml

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,46 @@ env:
44
- TYPESCRIPT_VERSION=next
55
- TYPESCRIPT_VERSION=4.0
66
- TYPESCRIPT_VERSION=3.9
7-
- TYPESCRIPT_VERSION=3.8
8-
- TYPESCRIPT_VERSION=3.7
9-
- TYPESCRIPT_VERSION=3.6
10-
- TYPESCRIPT_VERSION=3.5
117
install:
128
- npm ci --ignore-scripts
139
- npm install typescript@$TYPESCRIPT_VERSION
1410
script: npm run prepare
11+
12+
jobs:
13+
include:
14+
- env:
15+
- TYPESCRIPT_VERSION=3.8
16+
install:
17+
- npm ci --ignore-scripts
18+
- npm install typescript@$TYPESCRIPT_VERSION
19+
- sed -i -e 's/"cd type-tests.*"/"true"/' package.json
20+
- sed -i -e 's/@ts-expect-error/typings:expect-error/' type-tests/files/*
21+
- mv type-tests/types.test.disabled.ts type-tests/types.test.ts
22+
script: npm run prepare
23+
- env:
24+
- TYPESCRIPT_VERSION=3.7
25+
install:
26+
- npm ci --ignore-scripts
27+
- npm install typescript@$TYPESCRIPT_VERSION
28+
- sed -i -e 's/"cd type-tests.*"/"true"/' package.json
29+
- sed -i -e 's/@ts-expect-error/typings:expect-error/' type-tests/files/*
30+
- mv type-tests/types.test.disabled.ts type-tests/types.test.ts
31+
script: npm run prepare
32+
- env:
33+
- TYPESCRIPT_VERSION=3.6
34+
install:
35+
- npm ci --ignore-scripts
36+
- npm install typescript@$TYPESCRIPT_VERSION
37+
- sed -i -e 's/"cd type-tests.*"/"true"/' package.json
38+
- sed -i -e 's/@ts-expect-error/typings:expect-error/' type-tests/files/*
39+
- mv type-tests/types.test.disabled.ts type-tests/types.test.ts
40+
script: npm run prepare
41+
- env:
42+
- TYPESCRIPT_VERSION=3.5
43+
install:
44+
- npm ci --ignore-scripts
45+
- npm install typescript@$TYPESCRIPT_VERSION
46+
- sed -i -e 's/"cd type-tests.*"/"true"/' package.json
47+
- sed -i -e 's/@ts-expect-error/typings:expect-error/' type-tests/files/*
48+
- mv type-tests/types.test.disabled.ts type-tests/types.test.ts
49+
script: npm run prepare

docs/api/createAction.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ Every generated actionCreator has a `.match(action)` method that can be used to
145145
146146
This has different uses:
147147
148-
### As a TypeScript TypeGuard
148+
### As a TypeScript Type Guard
149149
150150
This `match` method is a [TypeScript type guard](https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards) and can be used to discriminate the `payload` type of an action.
151151

docs/api/createAsyncThunk.mdx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ const onClick = () => {
234234

235235
The thunks generated by `createAsyncThunk` **will always return a resolved promise** with either the `fulfilled` action object or `rejected` action object inside, as appropriate.
236236

237-
The calling logic may wish to treat these actions as if they were the original promise contents. Redux Toolkit exports an `unwrapResult` function that can be used to extract the `payload` or `error` from the action, and return or throw the result appropriately:
237+
The calling logic may wish to treat these actions as if they were the original promise contents. Redux Toolkit exports an `unwrapResult` function that can be used to extract the `payload` of a `fulfilled` action or to throw either the `error` or, if available, `payload` created by `rejectWithValue` from a `rejected` action:
238238

239239
```js
240240
import { unwrapResult } from '@reduxjs/toolkit'
@@ -244,7 +244,7 @@ const onClick = () => {
244244
dispatch(fetchUserById(userId))
245245
.then(unwrapResult)
246246
.then(originalPromiseResult => {})
247-
.catch(serializedError => {})
247+
.catch(rejectedValueOrSerializedError => {})
248248
}
249249
```
250250

@@ -437,7 +437,7 @@ const fetchUserById = createAsyncThunk(
437437
- Requesting a user by ID, with loading state, and only one request at a time:
438438

439439
```js
440-
import { createAsyncThunk, createSlice, unwrapResult } from '@reduxjs/toolkit'
440+
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
441441
import { userAPI } from './userAPI'
442442

443443
const fetchUserById = createAsyncThunk(
@@ -494,7 +494,7 @@ const UsersComponent = () => {
494494
const fetchOneUser = async userId => {
495495
try {
496496
const resultAction = await dispatch(fetchUserById(userId))
497-
const user = unwrapResult(resultAction)
497+
const user = resultAction.payload
498498
showToast('success', `Fetched ${user.name}`)
499499
} catch (err) {
500500
showToast('error', `Fetch failed: ${err.message}`)

docs/api/createSelector.mdx

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,44 @@ For more details on using `createSelector`, see:
1919
> **Note**: Prior to v0.7, RTK re-exported `createSelector` from [`selectorator`](https://github.com/planttheidea/selectorator), which
2020
> allowed using string keypaths as input selectors. This was removed, as it ultimately did not provide enough benefits, and
2121
> the string keypaths made static typing for selectors difficult.
22+
23+
# `createDraftSafeSelector`
24+
25+
In general, we recommend against using selectors inside of reducers:
26+
27+
- Selectors typically expect the entire Redux state object as an argument, while slice reducers only have access to a specific subset of the entire Redux state
28+
- Reselect's `createSelector` relies on reference comparisons to determine if inputs have changed, and if an Immer Proxy-wrapped draft value is passed in to a selector, the selector may see the same reference and think nothing has changed.
29+
30+
However, some users have requested the ability to create selectors that will work correctly inside of Immer-powered reducers. One use case for this might be collecting an ordered set of items when using `createEntityAdapter, such as`const orderedTodos = todosSelectors.selectAll(todosState)`, and then using`orderedTodos` in the rest of the reducer logic.
31+
32+
Besides re-exporting `createSelector`, RTK also exports a wrapped version of `createSelector` named `createDraftSafeSelector` that allows you to create selectors that can safely be used inside of `createReducer` and `createSlice` reducers with Immer-powered mutable logic. When used with plain state values, the selector will still memoize normally based on the inputs. But, when used with Immer draft values, the selector will err on the side of recalculating the results, just to be safe.
33+
34+
All selectors created by `entityAdapter.getSelectors` are "draft safe" selectors by default.
35+
36+
Example:
37+
38+
```js
39+
const selectSelf = (state: State) => state
40+
const unsafeSelector = createSelector(selectSelf, state => state.value)
41+
const draftSafeSelector = createDraftSafeSelector(
42+
selectSelf,
43+
state => state.value
44+
)
45+
46+
// in your reducer:
47+
48+
state.value = 1
49+
50+
const unsafe1 = unsafeSelector(state)
51+
const safe1 = draftSafeSelector(state)
52+
53+
state.value = 2
54+
55+
const unsafe2 = unsafeSelector(state)
56+
const safe2 = draftSafeSelector(state)
57+
```
58+
59+
After executing that, `unsafe1` and `unsafe2` will be of the same value, because the memoized selector was
60+
executed on the same object - but `safe2` will actually be different from `safe1` (with the updated value of `2`),
61+
because the safe selector detected that it was executed on a Immer draft object and recalculated using the current
62+
value instead of returning a cached value.

0 commit comments

Comments
 (0)