You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In this sample we are going to change our page component to add a hardcoded list of members.
3
+
In this sample we are going to add an Api to our application and integrate it into our Container component, replacing the previously added hardcoded data.
4
4
5
-
We will use as start up point _00 Boilerplate_.
5
+
We will use as start up point _01 Hardcoded list component.
6
6
7
7
Summary steps:
8
8
9
-
-Define the view model.
10
-
-Create a component to show a table with a list of members.
11
-
- Create a component to show a row that is part of the table component.
12
-
- Modify the page component to show a table with hardcoded members.
9
+
-Create a data model for the API.
10
+
-Implement an API call that fetches data from the web and parses it into the previously defined data model.
11
+
- Create an auxiliary mapper module to parse from the api data model to the view model used in the Container component tree.
12
+
- Modify the container component to use the API calls and the subsequently returned data.
13
13
14
14
# Prerequisites
15
15
@@ -19,205 +19,139 @@ Install [Node.js and npm](https://nodejs.org/en/) if they are not already instal
19
19
20
20
## Steps to build it
21
21
22
-
- Copy the content of the `00 Boilerplate` folder to an empty folder for the sample.
22
+
- Copy the content of the `01 Hardcoded list component` folder to an empty folder for the sample.
23
23
24
24
- Install the npm packages described in the `package.json` and verify that it works:
25
25
26
26
```
27
27
npm install
28
28
```
29
-
30
-
- Let's define our view model. As we are later going to obtain a list of GitHub members, we specify that a member will have an id, a name and an avatar URL. Therefore, our _viewModel.ts_ file will contain:
29
+
30
+
-
31
+
32
+
- We will start by creating a suitable folder structure for our new API.
33
+
```
34
+
.
35
+
└── api/
36
+
└── model/
37
+
├── index.ts
38
+
├── member.ts
39
+
├── memberApi.ts
40
+
└── index.ts
41
+
```
42
+
43
+
- First, we add an `api subfolder` inside `src`. Then, inside `src/api` we create a new subfolder named `src/api/model`
44
+
45
+
- Let's start by defining the data model used in our API. Our data source will be a list of GitHub members. As we know from the previous case, we want to be able to display the id, name and profile image (represented as an Url) inside our members page. Thus, the data that we really care to retrieve should hold 1 number property for the id, and 2 string properties for the user login name and avatar image Url respectively . Consequently, we will create a `member.ts` file inside `src/api/model` with the content below:
31
46
32
47
```javascript
33
48
exportinterfaceMemberEntity {
34
-
id : number;
35
-
name : string;
36
-
avatarUrl: string;
49
+
login: string;
50
+
id: number;
51
+
avatar_url: string;
37
52
}
38
53
```
39
54
40
-
-Now, we are going to create a folder named _components_, under _members_ folder.
55
+
-And since we want to be able to access this interface later from both the API call itself (to properly format the data fetched) and from our auxiliary mapper modulee (to ensure that we can parse from this interface to the one used internally in our view model), we will also define a barrel `index.ts` file for our `src/api/model` folder, as follows:
41
56
42
-
- Then, we will add some files for the components that we need to show a list of members in our page. Under _components_ folder, create _index.ts_, _memberRow.tsx_ and _memberTable.tsx_.
57
+
´´´javascript
58
+
export {MemberEntity} from './member';
59
+
´´´
43
60
44
-
-The _src_ folder structure should be like the following one:
61
+
-Next we can start working on our `memberApi.ts` file. We will import our data model from `./model` barrel index file. We will also need to define some constants to store the root Url for our data source service, and the specific endpoint we want to call to retrieve the list of members. We can do by adding the following lines.
- Let's create the component that will show a member's details in a row.
64
-
- The properties of our component will include just a member.
65
-
- Our component will return the HTML code that renders the member received in the properties argument.
66
-
- Therefore, we need to add the following code to our _memberRow.tsx_ file:
70
+
- We want to define a get/fetch REST call to retrieve our list of members from the server. In order to do this, we must send an aynchronous call to the server, using a Promise to store said data once it is available in our app. Thus, we define a `fetchMemberList` method that performs the aformentioned 'fetch' operation and parses the corresponding data, as follows:
-Now, let's create the component that will show the list of members. To do so, we need to import the MemberRow component into _memberTable.tsx_ and render it accordingly. In this case, the properties will be an array of members:
84
+
-As noted in the code above, we will first fetch the results from our Url endpoint, and then we will first check that the data could be retrieved successfully, parse said data into JSON, and finally resolve said data according to the API data model we have defined.
86
85
87
-
```javascript
88
-
import*asReactfrom'react';
89
-
import { MemberEntity } from'../viewModel';
90
-
import { MemberRow } from'./memberRow';
86
+
- Regarding thee `checkStatus` method, we will simply forward the response if we got an OK reply from the Backend. Otherwise, we will throw an error according to the status received. Notice that we do not need to wrap the returned value inside a Promise (for example, using `Promise.resolve()`), as the `then` call already returns a promise resolved with the data returned. Thus, we can chain then properly without incurring any typing errors on behalf of Typescript.
-Now, let's use barrel and export MemberTable in _./src/pages/members/components/index.ts_:
99
+
-If the members data was retrieved succesfully, we then take the corresponding JSON content.
120
100
121
101
```javascript
122
-
export { MemberTable } from'./memberTable';
102
+
constparseJSON= (response : Response) :any=> {
103
+
returnresponse.json();
104
+
}
105
+
123
106
```
124
107
125
-
- It's the moment to include our MemberTable in our _page.tsx_ component.
126
-
- We need to import MemberEntity.
127
-
- We need to define the properties: it will be the list of members.
128
-
- We need to convert the component from a function into a class.
108
+
- And finally, for each object in our data list (i.e. for each member in our members list), we will retrieve the three values we are interested in (using destructuring to make the code more concise), build a new object with these 3 values (using the short syntax for property assignment, i.e. `{id, login, avatar_url} equals {id:id, login:login, avatar_url:avatar_url})`), and finally we 'cast' our object into our api data model, as we do meet the required interface (types match).
129
109
130
-
```diff
131
-
import * as React from 'react';
132
-
+ import { MemberEntity } from './viewModel';
133
-
+ import { MemberTable } from './components';
134
-
135
-
+ interface Props {
136
-
+ memberList: MemberEntity[];
137
-
+ fetchMemberList: () => void;
138
-
+ }
139
-
140
-
- export const MemberListPage = () => (
141
-
- <h1>Hello from member list page</h1>
142
-
- );
143
-
144
-
+ export class MemberListPage extends React.Component<Props, {}> {
- We need to define the State: it will be the list of members.
160
-
- We need to convert the component from a function into a class.
161
120
162
-
```diff
163
-
import * as React from 'react';
164
-
import { MemberListPage } from './page';
165
-
+ import { MemberEntity } from './viewModel';
166
-
167
-
+ interface State {
168
-
+ memberList : MemberEntity[];
169
-
+ }
170
-
171
-
- export class MemberListContainer extends React.Component<{}, {}> {
172
-
- render() {
173
-
- return (
174
-
- <MemberListPage/>
175
-
- );
176
-
- }
177
-
- }
178
-
179
-
+ export class MemberListContainer extends React.Component<{}, State> {
180
-
+
181
-
+ constructor(props) {
182
-
+ super(props);
183
-
+ this.state = { memberList: [] };
184
-
+ }
185
-
+
186
-
+ render() {
187
-
+ return (
188
-
+ <MemberListPage
189
-
+ memberList={this.state.memberList}
190
-
+ />
191
-
+ );
192
-
+ }
193
-
+ }
194
-
```
121
+
- We have finished our API, now we need to do some changes on our container file and folder to properly expose the API to it.
195
122
196
-
-At this point, there is a piece missing: when our page is created, we need a call to get the list of members whenever it is ready. We will do it in _page.tsx_ using the method _componentDidMount()_.
123
+
-First, we will create a new file inside our `src/pages/members` folder called `mapper.ts`. This will be an auxiliary file that parses between our api data model and the view model used in our components. The code we need to add would be the following:
- The method `mapMemberListFromModelToVm` is the one that actually maps the members list retrieved from the Backend into the data model used in our components. Internally, it will call `mapMemberFromModelToVm` to process and parse each member object inside the list. We do not need to use this parsing method outside of our container, so we will not be adding any methods from `mapper.ts` into the `index.ts` file of our container folder.
209
143
210
-
render() {
211
-
return (
212
-
<MemberTable
213
-
memberList={this.props.memberList}
214
-
/>
215
-
);
216
-
}
217
-
}
144
+
- The last steps remaining will revolve around changing the code of our `container.tsx` component to use the new API endpoint alongside our mapper's parsing method. First, we will start by adding the new dependencies to our file header.
145
+
146
+
```diff
147
+
import * as React from 'react';
148
+
import { MemberListPage } from './page';
149
+
import { MemberEntity } from './viewModel';
150
+
+ import { fetchMemberList } from '../../api';
151
+
+ import { mapMemberListFromModelToVm } from './mapper';
218
152
```
219
153
220
-
-Now, what we need to do is to simulate how to get the list of members. As it should normally be an asynchronous call, we will use a timeout to return a list of hardcoded members in _container.tsx_.
154
+
-And finally, we will replace the hardcoded block of the `fetchMembers` method to use instead a callto our `fetchMemberList` API endpoint
221
155
222
156
```diff
223
157
export class MemberListContainer extends React.Component<{}, State> {
0 commit comments