mirror of
https://github.com/microsoft/frontend-bootcamp.git
synced 2026-01-26 14:56:42 +08:00
Day 2 step 5 updates (#83)
This commit is contained in:
committed by
Kenneth Chau
parent
945bc22f27
commit
681f098e78
@@ -2,74 +2,74 @@
|
|||||||
|
|
||||||
[Lessons](../) | [Exercise](./exercise/) | [Demo](./demo/)
|
[Lessons](../) | [Exercise](./exercise/) | [Demo](./demo/)
|
||||||
|
|
||||||
In this step, we will look at solving the problems of complex application (as mentioned in Step 4) with a library called Redux.
|
In this step, we will look at solving the problems of complex applications (as mentioned in Step 4) with a library called [Redux](https://redux.js.org).
|
||||||
|
|
||||||
1. Introduction to Redux
|
1. Introduction to Redux
|
||||||
2. Why Use Redux?
|
2. Why use Redux?
|
||||||
3. Creating the Redux store
|
3. Creating the Redux store
|
||||||
4. Writing reducers
|
4. Writing reducers
|
||||||
5. Dispatching actions
|
5. Dispatching actions
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Introduction to Redux
|
## Introduction to Redux
|
||||||
|
|
||||||
As a reminder, the problem that we want to address are:
|
As a reminder, the problems that we want to address are:
|
||||||
|
|
||||||
1. Data needs to be passed down from component to component via props. Even when some components do not need to know about some data.
|
1. Data needs to be passed down from component to component via props, even when some intermediate components don't use all of the data.
|
||||||
2. Shared data can be changed by various actors (user interaction, updates from server), and there is no coordination of these changes
|
2. Shared data can be changed by various actors (user interaction, updates from server), and there is no coordination of these changes.
|
||||||
|
|
||||||
Redux is an implementation of the Flux architectural pattern:
|
Redux is an implementation of the Flux architectural pattern:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
### View
|
### View
|
||||||
|
|
||||||
A view is a React component that consumes the store as its data.
|
A view is a React component that consumes the store as its data.
|
||||||
|
|
||||||
### Action
|
### Actions
|
||||||
|
|
||||||
[Actions](https://redux.js.org/basics/actions) are serializable JSON messages that represent some event, such as a user's action or a network request. With the aid of _reducers_, they affect the overall state. At the minimum, it should contain a `type` key. Sometimes it contains additional data as a _payload_.
|
[Actions](https://redux.js.org/basics/actions) are serializable JSON messages that represent some event, such as a user's action or a network request. With the aid of **reducers**, they affect the overall state. At minimum, an action should contain a `type` key. Sometimes it contains additional data as a **payload**.
|
||||||
|
|
||||||
### Store
|
### Store
|
||||||
|
|
||||||
The [store](https://redux.js.org/basics/store) consists of a **state tree**, a **dispatcher**, and **reducers**.
|
The [store](https://redux.js.org/basics/store) consists of a **state tree**, a **dispatcher**, and **reducers**.
|
||||||
|
|
||||||
1. The **state tree** is a _singleton_, _serializable_, _immutable_ nested json data. It is updated from one snapshot to another through `reducers`.
|
1. The **state tree** is a _singleton_, _serializable_, _immutable_ nested JSON structure. It is updated from one snapshot to another using reducers.
|
||||||
|
|
||||||
2. The **dispatcher** accepts actions passing them to the reducers.
|
2. The [**dispatcher**](https://redux.js.org/basics/data-flow) accepts actions, passing them to the reducers.
|
||||||
|
|
||||||
3. **Reducers** are functions that take in the current state tree and an action, producing the next snapshot of the state tree. This is the only way to update the state tree.
|
3. [**Reducers**](https://redux.js.org/basics/reducers) are functions that take in the current state tree and an action, producing the next snapshot of the state tree. This is the only way to update the state tree.
|
||||||
|
|
||||||
## Why Use Redux?
|
## Why use Redux?
|
||||||
|
|
||||||
There are lots of alternatives available, but here are some really good reasons to go with Redux:
|
There are lots of alternatives available, but here are some really good reasons to go with Redux:
|
||||||
|
|
||||||
1. For more complex applications, Flux pattern forces code to be written in a way that is easy to reason about
|
1. For more complex applications, Flux pattern forces code to be written in a way that is easy to reason about
|
||||||
2. There maybe a need to serialize the application state to be transmitted across the wire somehow
|
2. There may be a need to serialize the application state to be transmitted across the network somehow
|
||||||
3. Dev tooling is really amazing
|
3. Dev tooling is really amazing
|
||||||
4. Popularity of the framework means the ecosystem is mature at this point
|
4. Popularity of the framework means the ecosystem is mature at this point
|
||||||
|
|
||||||
# Creating the Redux store
|
## Using Redux
|
||||||
|
|
||||||
The [`createStore()`](https://redux.js.org/api/createstore) function is provided by Redux to create a store. In general, an application would just have one single store. It takes in the reducer and an initial snapshot of the state tree.
|
### Creating the Redux store
|
||||||
|
|
||||||
|
The [`createStore()`](https://redux.js.org/api/createstore) function is provided by Redux to create a store. In general, an application has a single store. The function typically takes in the main reducer and an initial snapshot of the state tree.
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
const store = createStore(reducer, initialState);
|
const store = createStore(reducer, initialState);
|
||||||
```
|
```
|
||||||
|
|
||||||
# Writing Reducers
|
### Writing reducers
|
||||||
|
|
||||||
We will write our reducers with the help of some utilities from the official `redux-starter-kit`. Here is how we will write our reducers:
|
We'll write our reducers with the help of some utilities from the official [`redux-starter-kit`](https://redux-starter-kit.js.org/), which greatly decreases the amount of boilerplate needed. The process for designing and implementing reducers is as follows:
|
||||||
|
|
||||||
## 1. Organize reducers according to the keys of the state tree object:
|
#### 1. Organize reducers according to the keys of the state tree object
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { createReducer } from 'redux-starter-kit';
|
import { createReducer } from 'redux-starter-kit';
|
||||||
|
|
||||||
|
// first argument: initial state
|
||||||
|
// second argument: object whose keys correspond to possible values of action.type
|
||||||
const todosReducer = createReducer({}, {
|
const todosReducer = createReducer({}, {
|
||||||
// first argument is the initial state
|
|
||||||
// second argument is an object where the keys corresponds to the "action.type"
|
|
||||||
addTodo: (state, action) => ...
|
addTodo: (state, action) => ...
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -80,19 +80,19 @@ const filterReducer = createReducer('all', {
|
|||||||
const reducer = combineReducer({
|
const reducer = combineReducer({
|
||||||
todos: todosReducer,
|
todos: todosReducer,
|
||||||
filter: filterReducer
|
filter: filterReducer
|
||||||
})
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
## 2. Write the reducers with mutables.
|
#### 2. Write the reducers with mutables
|
||||||
|
|
||||||
`createReducer()` will automatically translate all the mutations to the state into immutable snapshots (!!!!!):
|
In plain Redux, reducers must make a copy of the state before making modifications, but `createReducer()` will automatically translate all the mutations to the state into immutable snapshots (!!!!!):
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
|
// first argument: initial state
|
||||||
|
// second argument: object whose keys correspond to possible values of action.type
|
||||||
const todosReducer = createReducer(
|
const todosReducer = createReducer(
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
// first argument is the initial state
|
|
||||||
// second argument is an object where the keys corresponds to the "action.type"
|
|
||||||
addTodo: (state, action) => {
|
addTodo: (state, action) => {
|
||||||
state[action.id] = { label: action.label, completed: false };
|
state[action.id] = { label: action.label, completed: false };
|
||||||
}
|
}
|
||||||
@@ -100,9 +100,9 @@ const todosReducer = createReducer(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
# Dispatching Actions
|
### Dispatching actions
|
||||||
|
|
||||||
Dispatching action will pass the action and the current state to the _reducers_. The root _reducer_ will produce a new snapshot for the entire state tree. We can inspect the affected snapshot with the help of `getState()`.
|
Dispatching an action will pass the action and the current state to the reducers. The root reducer will produce a new snapshot of the entire state tree. We can inspect the affected snapshot with the help of `getState()`.
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
const store = createStore(reducer, initialState);
|
const store = createStore(reducer, initialState);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
If you don't already have the app running, start it by running `npm start` from the root of the `frontend-bootcamp` folder. Click the "exercise" link under day 2 step 5 to see results.
|
If you don't already have the app running, start it by running `npm start` from the root of the `frontend-bootcamp` folder. Click the "exercise" link under day 2 step 5 to see results.
|
||||||
|
|
||||||
1. First, take a look at the store interface in `exercise/src/store/index.ts`. Note that the `Store` interface has two keys: `todos` and `filter`. We'll concentrate on `todos`, which is an object where the keys are string IDs and the values are of a `TodoItem` type.
|
1. First, take a look at the store interface in `exercise/src/store/index.ts`. Note that the `Store` interface has two keys: `todos` and `filter`. We'll concentrate on `todos`, which is an object where the keys are string IDs and the values are of type `TodoItem`.
|
||||||
|
|
||||||
2. Open `exercise/src/reducers/index.ts` and fill in the missing case statements for the switch on `action.type`.
|
2. Open `exercise/src/reducers/index.ts` and fill in the missing case statements for the switch on `action.type`.
|
||||||
|
|
||||||
@@ -12,6 +12,6 @@ If you don't already have the app running, start it by running `npm start` from
|
|||||||
|
|
||||||
4. Take a look what is written in the console (F12 on PC, cmd-option-I on Mac).
|
4. Take a look what is written in the console (F12 on PC, cmd-option-I on Mac).
|
||||||
|
|
||||||
5. Install the [Chrome](https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd) or [Firefox](https://addons.mozilla.org/en-US/firefox/addon/reduxdevtools/) extensions
|
5. Install the Redux DevTools [Chrome](https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd) or [Firefox](https://addons.mozilla.org/en-US/firefox/addon/reduxdevtools/) extensions
|
||||||
|
|
||||||
6. Observe the state changes, try doing "time travel"
|
6. Observe the state changes and try doing "time travel"
|
||||||
|
|||||||
Reference in New Issue
Block a user