Skip to content

Commit

Permalink
Stop using backticks with Promise
Browse files Browse the repository at this point in the history
  • Loading branch information
markerikson committed Jul 27, 2024
1 parent 696c01d commit 7b21b84
Show file tree
Hide file tree
Showing 4 changed files with 17 additions and 17 deletions.
24 changes: 12 additions & 12 deletions docs/tutorials/essentials/part-5-async-logic.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ Thunks are typically written in ["slice" files](./part-2-app-structure.md#redux-

### Writing Async Thunks

Thunks may have async logic inside of them, such as `setTimeout`, `Promise`s, and `async/await`. This makes them a good place to put HTTP calls to a server API.
Thunks may have async logic inside of them, such as `setTimeout`, Promises, and `async/await`. This makes them a good place to put HTTP calls to a server API.

Data fetching logic for Redux typically follows a predictable pattern:

Expand Down Expand Up @@ -264,9 +264,9 @@ const logAndAdd = (amount: number): AppThunk => {

#### Typing `createAsyncThunk`

For `createAsyncThunk` specifically: if your payload function accepts an argument, provide a type for that argument, like `async (userId: string)`.
For `createAsyncThunk` specifically: if your payload function accepts an argument, **provide a type for that argument, like `async (userId: string)`**. You do not need to provide a return type by default - TS will infer the return type automatically.

If you need to access `dispatch` or `getState` inside of `createAsyncThunk, RTK provides a way to define a "pre-typed" version that has the correct `dispatch`and`getState`types built in by calling`createAsyncThunk.withTypes()`, equivalent to how we defined pre-typed versions of `useSelector`and`useDispatch`. We'll create a new `src/app/withTypes` files, and export it from there:
If you need to access `dispatch` or `getState` inside of `createAsyncThunk`, RTK provides a way to define a "pre-typed" version that has the correct `dispatch` and `getState`types built in by calling `createAsyncThunk.withTypes()`, equivalent to how we defined pre-typed versions of `useSelector` and `useDispatch`. We'll create a new `src/app/withTypes` files, and export it from there:

```ts title="app/withTypes.ts"
import { createAsyncThunk } from '@reduxjs/toolkit'
Expand Down Expand Up @@ -435,9 +435,9 @@ const initialState: PostsState = {
`createAsyncThunk` accepts two arguments:

- A string that will be used as the prefix for the generated action types
- A "payload creator" callback function that should return a `Promise` containing some data, or a rejected `Promise` with an error
- A "payload creator" callback function that should return a Promise containing some data, or a rejected Promise with an error

The payload creator will usually make an HTTP request of some kind, and can either return the `Promise` from the HTTP request directly, or extract some data from the API response and return that. We typically write this using the JS `async/await` syntax, which lets us write functions that use promises while using standard `try/catch` logic instead of `somePromise.then()` chains.
The payload creator will usually make an HTTP request of some kind, and can either return the Promise from the HTTP request directly, or extract some data from the API response and return that. We typically write this using the JS `async/await` syntax, which lets us write functions that use promises while using standard `try/catch` logic instead of `somePromise.then()` chains.

In this case, we pass in `'posts/fetchPosts'` as the action type prefix.

Expand All @@ -449,7 +449,7 @@ If we try calling `dispatch(fetchPosts())`, the `fetchPosts` thunk will first di

We can listen for this action in our reducer and mark the request status as `'pending'`.

Once the `Promise` resolves, the `fetchPosts` thunk takes the `response.data` array we returned from the callback, and dispatches a `'posts/fetchPosts/fulfilled'` action containing the posts array as `action.payload`:
Once the Promise resolves, the `fetchPosts` thunk takes the `response.data` array we returned from the callback, and dispatches a `'posts/fetchPosts/fulfilled'` action containing the posts array as `action.payload`:

![`createAsyncThunk`: posts pending action](/img/tutorials/essentials/devtools-posts-fulfilled.png)

Expand Down Expand Up @@ -516,7 +516,7 @@ const postsSlice = createSlice({
})
```

We'll handle all three action types that could be dispatched by the thunk, based on the `Promise` we returned:
We'll handle all three action types that could be dispatched by the thunk, based on the Promise we returned:

- When the request starts, we'll set the `status` enum to `'pending'`
- If the request succeeds, we mark the `status` as `'succeeded'`, and add the fetched posts to `state.posts`
Expand Down Expand Up @@ -612,7 +612,7 @@ export const fetchPosts = createAppAsyncThunk(
const response = await client.get<Post[]>('/fakeApi/posts')
return response.data
},
/// highlight-start
// highlight-start
{
condition(arg, thunkApi) {
const postsStatus = selectPostsStatus(thunkApi.getState())
Expand Down Expand Up @@ -806,7 +806,7 @@ export const createAppSlice = buildCreateSlice({

That gives you a version of `createSlice` with the ability to write thunks inside.

Finally, we can use that `createAppSlice` method to define our `postsSlice` with the `fetchPosts` thunk inside. When we do that, a couple other things changeg:
Finally, we can use that `createAppSlice` method to define our `postsSlice` with the `fetchPosts` thunk inside. When we do that, a couple other things change:

- We can't pass in the `RootState` generic directly, so we have to do `getState() as RootState` to cast it
- We can pass in all of the reducers that handle the thunk actions as part of the options to `create.asyncThunk()`, and remove those from the `extraReducers` field:
Expand Down Expand Up @@ -846,7 +846,7 @@ const postsSlice = createAppSlice({
state.posts.push(...action.payload)
},
rejected: (state, action) => {
state.status = 'failed'
state.status = 'rejected'
state.error = action.error.message ?? 'Unknown Error'
}
}
Expand Down Expand Up @@ -1104,8 +1104,8 @@ As a reminder, here's what we covered in this section:
- The typical pattern is dispatching a "pending" action before the call, then either a "success" containing the data or a "failure" action containing the error
- Loading state should usually be stored as an enum, like `'idle' | 'pending' | 'succeeded' | 'rejected'`
- **Redux Toolkit has a `createAsyncThunk` API that dispatches these actions for you**
- `createAsyncThunk` accepts a "payload creator" callback that should return a `Promise`, and generates `pending/fulfilled/rejected` action types automatically
- Generated action creators like `fetchPosts` dispatch those actions based on the `Promise` you return
- `createAsyncThunk` accepts a "payload creator" callback that should return a Promise, and generates `pending/fulfilled/rejected` action types automatically
- Generated action creators like `fetchPosts` dispatch those actions based on the Promise you return
- You can listen for these action types in `createSlice` using the `extraReducers` field, and update the state in reducers based on those actions.
- `createAsyncThunk` has a `condition` option that can be used to cancel a request based on the Redux state
- Thunks can return promises. For `createAsyncThunk` specifically, you can `await dispatch(someThunk()).unwrap()` to handle the request success or failure at the component level.
Expand Down
2 changes: 1 addition & 1 deletion docs/tutorials/essentials/part-7-rtk-query-basics.md
Original file line number Diff line number Diff line change
Expand Up @@ -639,7 +639,7 @@ Mutation hooks return an array with two values:

We can replace the existing thunk dispatch and component loading state with the trigger function and `isLoading` flag from the `useAddNewPostMutation` hook, and the rest of the component stays the same.

As with the previous thunk dispatch, we call `addNewPost` with the initial post object. This returns a special `Promise` with a `.unwrap()` method, and we can `await addNewPost().unwrap()` to handle any potential errors with a standard `try/catch` block.
As with the previous thunk dispatch, we call `addNewPost` with the initial post object. This returns a special Promise with a `.unwrap()` method, and we can `await addNewPost().unwrap()` to handle any potential errors with a standard `try/catch` block.

## Refreshing Cached Data

Expand Down
2 changes: 1 addition & 1 deletion docs/tutorials/essentials/part-8-rtk-query-advanced.md
Original file line number Diff line number Diff line change
Expand Up @@ -880,7 +880,7 @@ export const apiSlice = createApi({
})
```
The `onQueryStarted` handler receives two parameters. The first is the cache key `arg` that was passed when the request started. The second is an object that contains some of the same fields as the `thunkApi` in `createAsyncThunk` ( `{dispatch, getState, extra, requestId}`), but also a `Promise` called `queryFulfilled`. This `Promise` will resolve when the request returns, and either fulfill or reject based on the request.
The `onQueryStarted` handler receives two parameters. The first is the cache key `arg` that was passed when the request started. The second is an object that contains some of the same fields as the `thunkApi` in `createAsyncThunk` ( `{dispatch, getState, extra, requestId}`), but also a Promise called `queryFulfilled`. This Promise will resolve when the request returns, and either fulfill or reject based on the request.
The API slice object includes a `updateQueryData` util function that lets us update cached values. It takes three arguments: the name of the endpoint to update, the same cache key value used to identify the specific cached data, and a callback that updates the cached data. **`updateQueryData` uses Immer, so you can "mutate" the drafted cache data the same way you would in `createSlice`**.
Expand Down
6 changes: 3 additions & 3 deletions docs/tutorials/fundamentals/part-8-modern-redux.md
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,7 @@ Here's how our code looks with all the slices converted:

We've seen how we can [write thunks that dispatch "loading", "request succeeded", and "request failed" actions](./part-7-standard-patterns.md#loading-state-enum-values). We had to write action creators, action types, _and_ reducers to handle those cases.

Because this pattern is so common, **Redux Toolkit has a `createAsyncThunk` API that will generate these thunks for us**. It also generates the action types and action creators for those different request status actions, and dispatches those actions automatically based on the resulting `Promise`.
Because this pattern is so common, **Redux Toolkit has a `createAsyncThunk` API that will generate these thunks for us**. It also generates the action types and action creators for those different request status actions, and dispatches those actions automatically based on the resulting Promise.

:::tip

Expand All @@ -470,7 +470,7 @@ Let's replace our `fetchTodos` thunk by generating a thunk with `createAsyncThun
`createAsyncThunk` accepts two arguments:

- A string that will be used as the prefix for the generated action types
- A "payload creator" callback function that should return a `Promise`. This is often written using the `async/await` syntax, since `async` functions automatically return a promise.
- A "payload creator" callback function that should return a Promise. This is often written using the `async/await` syntax, since `async` functions automatically return a promise.

```js title="src/features/todos/todosSlice.js"
// highlight-next-line
Expand Down Expand Up @@ -579,7 +579,7 @@ While we won't cover `createAsyncThunk` in more detail here, a few other quick n

- You can only pass one argument to the thunk when you dispatch it. If you need to pass multiple values, pass them in a single object
- The payload creator will receive an object as its second argument, which contains `{getState, dispatch}`, and some other useful values
- The thunk dispatches the `pending` action before running your payload creator, then dispatches either `fulfilled` or `rejected` based on whether the `Promise` you return succeeds or fails
- The thunk dispatches the `pending` action before running your payload creator, then dispatches either `fulfilled` or `rejected` based on whether the Promise you return succeeds or fails

## Normalizing State

Expand Down

0 comments on commit 7b21b84

Please sign in to comment.