Skip to content

Commit 507f41c

Browse files
committed
Merge branch 'master' into v1.3.0-integration
# Conflicts: # docs/usage/usage-guide.md # website/src/css/custom.css
2 parents dd8e44a + 4bbe51b commit 507f41c

File tree

2 files changed

+129
-5
lines changed

2 files changed

+129
-5
lines changed

docs/usage/usage-guide.md

Lines changed: 77 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -525,9 +525,84 @@ This CodeSandbox example demonstrates the problem:
525525

526526
<iframe src="https://codesandbox.io/embed/rw7ppj4z0m" style={{ width: '100%', height: '500px', border: 0, borderRadius: '4px', overflow: 'hidden' }} sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
527527

528-
If you encounter this, you may need to restructure your code in a way that avoids the circular references.
528+
If you encounter this, you may need to restructure your code in a way that avoids the circular references. This will usually require extracting shared code to a separate common file that both modules can import and use. In this case, you might define some common action types in a separate file using `createAction`, import those action creators into each slice file, and handle them using the `extraReducers` argument.
529529

530-
## Managing Async Requests
530+
The article [How to fix circular dependency issues in JS](https://medium.com/visual-development/how-to-fix-nasty-circular-dependency-issues-once-and-for-all-in-javascript-typescript-a04c987cf0de) has additional info and examples that can help with this issue.
531+
532+
## Asynchronous Logic and Data Fetching
533+
534+
### Using Middleware to Enable Async Logic
535+
536+
By itself, a Redux store doesn't know anything about async logic. It only knows how to synchronously dispatch actions, update the state by calling the root reducer function, and notify the UI that something has changed. Any asynchronicity has to happen outside the store.
537+
538+
But, what if you want to have async logic interact with the store by dispatching or checking the current store state? That's where [Redux middleware](https://redux.js.org/advanced/middleware) come in. They extend the store, and allow you to:
539+
540+
- Execute extra logic when any action is dispatched (such as logging the action and state)
541+
- Pause, modify, delay, replace, or halt dispatched actions
542+
- Write extra code that has access to `dispatch` and `getState`
543+
- Teach `dispatch` how to accept other values besides plain action objects, such as functions and promises, by intercepting them and dispatching real action objects instead
544+
545+
[The most common reason to use middleware is to allow different kinds of async logic to interact with the store](https://redux.js.org/faq/actions#how-can-i-represent-side-effects-such-as-ajax-calls-why-do-we-need-things-like-action-creators-thunks-and-middleware-to-do-async-behavior). This allows you to write code that can dispatch actions and check the store state, while keeping that logic separate from your UI.
546+
547+
There are many kinds of async middleware for Redux, and each lets you write your logic using different syntax. The most common async middleware are:
548+
549+
- [`redux-thunk`](https://github.com/reduxjs/redux-thunk), which lets you write plain functions that may contain async logic directly
550+
- [`redux-saga`](https://github.com/redux-saga/redux-saga), which uses generator functions that return descriptions of behavior so they can be executed by the middleware
551+
- [`redux-observable`](https://github.com/redux-observable/redux-observable/), which uses the RxJS observable library to create chains of functions that process actions
552+
553+
[Each of these libraries has different use cases and tradeoffs](https://redux.js.org/faq/actions#what-async-middleware-should-i-use-how-do-you-decide-between-thunks-sagas-observables-or-something-else).
554+
555+
**We recommend [using the Redux Thunk middleware as the standard approach](https://github.com/reduxjs/redux-thunk)**, as it is sufficient for most typical use cases (such as basic AJAX data fetching). In addition, use of the `async/await` syntax in thunks makes them easier to read.
556+
557+
**The Redux Toolkit `configureStore` function [automatically sets up the thunk middleware by default](../api/getDefaultMiddleware.md)**, so you can immediately start writing thunks as part of your application code.
558+
559+
### Defining Async Logic in Slices
560+
561+
Redux Toolkit does not currently provide any special APIs or syntax for writing thunk functions. In particular, **they cannot be defined as part of a `createSlice()` call**. You have to write them separate from the reducer logic, exactly the same as with plain Redux code.
562+
563+
564+
Thunks typically dispatch plain actions, such as `dispatch(dataLoaded(response.data))`.
565+
566+
Many Redux apps have structured their code using a "folder-by-type" approach. In that structure, thunk action creators are usually defined in an "actions" file, alongside the plain action creators.
567+
568+
Because we don't have separate "actions" files, **it makes sense to write these thunks directly in our "slice" files**. That way, they have access to the plain action creators from the slice, and it's easy to find where the thunk function lives.
569+
570+
A typical slice file that includes thunks would look like this:
571+
572+
```js
573+
// First, define the reducer and action creators via `createSlice`
574+
const usersSlice = createSlice({
575+
name: 'users',
576+
initialState: {
577+
loading: 'idle',
578+
users: []
579+
},
580+
reducers: {
581+
usersLoading(state, action) {
582+
// Use a "state machine" approach for loading state instead of booleans
583+
if (state.loading === 'idle') {
584+
state.loading = 'pending'
585+
}
586+
},
587+
usersReceived(state, action) {
588+
if (state.loading === 'pending') {
589+
state.loading = 'idle'
590+
state.users = action.payload
591+
}
592+
}
593+
}
594+
})
595+
596+
// Destructure and export the plain action creators
597+
export const { usersLoading, usersReceived } = usersSlice.actions
598+
599+
// Define a thunk that dispatches those action creators
600+
const fetchUsers = () => async dispatch => {
601+
dispatch(usersLoading())
602+
const response = await usersAPI.fetchAll()
603+
dispatch(usersReceived(response.data))
604+
}
605+
```
531606

532607
### Redux Data Fetching Patterns
533608

@@ -545,17 +620,14 @@ A typical implementation might look like:
545620
const getRepoDetailsStarted = () => ({
546621
type: "repoDetails/fetchStarted"
547622
})
548-
549623
const getRepoDetailsSuccess = (repoDetails) => {
550624
type: "repoDetails/fetchSucceeded",
551625
payload: repoDetails
552626
}
553-
554627
const getRepoDetailsFailed = (error) => {
555628
type: "repoDetails/fetchFailed",
556629
error
557630
}
558-
559631
const fetchIssuesCount = (org, repo) => async dispatch => {
560632
dispatch(getRepoDetailsStarted())
561633
try {

website/src/css/custom.css

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,22 @@
2121
--ifm-blockquote-color-dark: #cbddea;
2222

2323
--ifm-pre-background: rgb(39, 40, 34);
24+
25+
--ra-admonition-color: #ecf4f9;
26+
--ra-admonition-color-dark: #2a98b9;
27+
28+
--ra-admonition-color-important: #2a98b9;
29+
30+
--ra-admonition-color-success: #f1fdf9;
31+
--ra-admonition-color-success-dark: #00bf88;
32+
33+
--ra-admonition-color-caution: #fffbf5;
34+
--ra-admonition-color-caution-dark: #f0ad4e;
35+
36+
--ra-admonition-color-error: #fff2f2;
37+
--ra-admonition-color-error-dark: #d9534f;
38+
39+
--ra-admonition-icon-color: black !important;
2440
}
2541

2642
@media screen and (max-width: 996px) {
@@ -111,3 +127,39 @@ a:visited {
111127
.menu .menu__list-item.menu__list-item--collapsed .menu__link--sublist:after {
112128
transform: rotateZ(90deg);
113129
}
130+
131+
.admonition {
132+
color: var(--ifm-font-base-color);
133+
border-radius: var(--ifm-global-radius);
134+
border-left: 6px solid var(--ra-admonition-color-dark);
135+
}
136+
137+
.admonition.admonition-note,
138+
.admonition.admonition-info,
139+
.admonition.admonition-important,
140+
.admonition.admonition-secondary {
141+
--ra-admonition-color: #ecf4f9;
142+
background-color: var(--ra-admonition-color);
143+
}
144+
145+
.admonition.admonition-success,
146+
.admonition.admonition-tip {
147+
background-color: var(--ra-admonition-color-success);
148+
border-left-color: var(--ra-admonition-color-success-dark);
149+
}
150+
151+
.admonition.admonition-caution {
152+
background-color: var(--ra-admonition-color-caution);
153+
border-left-color: var(--ra-admonition-color-caution-dark);
154+
}
155+
156+
.admonition.admonition-warning,
157+
.admonition.admonition-danger {
158+
background-color: var(--ra-admonition-color-error);
159+
border-left-color: var(--ra-admonition-color-error-dark);
160+
}
161+
162+
.admonition .admonition-icon svg {
163+
fill: black;
164+
stroke: black;
165+
}

0 commit comments

Comments
 (0)