teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

4

テキスト追加

2021/11/25 14:02

投稿

退会済みユーザー
answer CHANGED
@@ -95,4 +95,81 @@
95
95
  ```
96
96
  先の(1)で挙げたコードでは、mergeの第三引数を、postIdの最大値`maxPostId`にしていましたが、postの個数の上限値`maxPostCount` に変更しました。
97
97
 
98
- - **動作確認のサンプル** ???? [tera: 370866 without lodash](https://codepen.io/kilesa/pen/KKvjBvN?editors=0010) @codepen
98
+ - **動作確認のサンプル** ???? [tera: 370866 without lodash](https://codepen.io/kilesa/pen/KKvjBvN?editors=0010) @codepen
99
+
100
+
101
+ ### 追記2
102
+
103
+ 上記の回答で、codepenに挙げたコード(のlodashを使うほう)をお手元で試すには、以下の手順で実行できるかと思います。
104
+
105
+ #### (1) 依存モジュールのインストール
106
+
107
+ ```shell
108
+ npm install lodash
109
+ ```
110
+
111
+ axios はすでにインスト−ルされているかと思いますが、まだであれば、
112
+
113
+ ```shell
114
+ npm install axios
115
+ ```
116
+
117
+ #### (2) src/components/ApiFetch.js を作成
118
+
119
+ 以下のように作成します。
120
+ ```jsx
121
+ import { useEffect, useState } from 'react';
122
+ import axios from 'axios';
123
+ import _ from 'lodash';
124
+
125
+ const POSTS_URL = 'https://jsonplaceholder.typicode.com/posts';
126
+ const COMMENTS_URL = 'https://jsonplaceholder.typicode.com/comments';
127
+
128
+ const merge = (posts, comments, maxPostId) => {
129
+
130
+ const filteredComments = comments.filter(({ postId }) => postId <= maxPostId);
131
+
132
+ const groupByPost = _(filteredComments)
133
+ .groupBy('postId')
134
+ .mapValues(
135
+ (comments, postId) => ({
136
+ ...posts.find(({ id }) => id === +postId),
137
+ comments
138
+ })
139
+ )
140
+ .value();
141
+
142
+ return groupByPost;
143
+ }
144
+
145
+ const ApiFetch = () => {
146
+
147
+ const [posts, setPosts] = useState({});
148
+
149
+ useEffect(() => {
150
+ const urls = [POSTS_URL, COMMENTS_URL];
151
+ const fetchers = urls.map(url => axios.get(url));
152
+ Promise.all(fetchers).then(([{ data: posts }, { data: comments }]) => {
153
+ const mergedPosts = merge(posts, comments, 50);
154
+ setPosts(mergedPosts);
155
+ });
156
+ }, []);
157
+
158
+ return (
159
+ <pre id="posts">
160
+ {JSON.stringify(posts, null, 4)}
161
+ </pre>
162
+ );
163
+ }
164
+
165
+ export default ApiFetch;
166
+
167
+ ```
168
+
169
+ ### (3) App.jsからApiFetchをimport
170
+
171
+ これで、`App.js`で、
172
+ ```javascript
173
+ import ApiFetch from './components/ApiFetch';
174
+ ```
175
+ とすることで、Appの返すJSXの中で、`<ApiFetch />` をどこかに書けば、動作確認できると思われます。

3

テキスト追加

2021/11/25 14:02

投稿

退会済みユーザー
answer CHANGED
@@ -85,16 +85,14 @@
85
85
  ```javascript
86
86
  const merge = (posts, comments, maxPostCount) =>
87
87
  posts.slice(0, maxPostCount)
88
- .reduce((obj, post) => (
88
+ .reduce((obj, post) => {
89
- {
90
- ...obj,
91
- [post.id]: {
89
+ obj[post.id] = {
92
- ...post,
90
+ ...post,
93
- comments: comments.filter(({ postId }) => post.id === postId)
91
+ comments: comments.filter(({ postId }) => post.id === postId)
94
- }
92
+ };
95
- }
93
+ return obj;
96
- ), {});
94
+ }, {});
97
95
  ```
98
96
  先の(1)で挙げたコードでは、mergeの第三引数を、postIdの最大値`maxPostId`にしていましたが、postの個数の上限値`maxPostCount` に変更しました。
99
97
 
100
- - **動作確認のサンプル** ???? [tera: 370866 without lodash](https://codepen.io/kilesa/pen/QWMXxxe?editors=0010) @codepen
98
+ - **動作確認のサンプル** ???? [tera: 370866 without lodash](https://codepen.io/kilesa/pen/KKvjBvN?editors=0010) @codepen

2

テキスト追加

2021/11/24 22:51

投稿

退会済みユーザー
answer CHANGED
@@ -75,4 +75,26 @@
75
75
  + link.setAttribute('download', 'mergedPosts.json');
76
76
  + link.click();
77
77
  });
78
- ```
78
+ ```
79
+
80
+
81
+ ### 追記
82
+
83
+ 上記の (1) で、lodash を使うコードを回答しましたが、lodashを使わない `merge`関数のコード例も挙げておきます。
84
+
85
+ ```javascript
86
+ const merge = (posts, comments, maxPostCount) =>
87
+ posts.slice(0, maxPostCount)
88
+ .reduce((obj, post) => (
89
+ {
90
+ ...obj,
91
+ [post.id]: {
92
+ ...post,
93
+ comments: comments.filter(({ postId }) => post.id === postId)
94
+ }
95
+ }
96
+ ), {});
97
+ ```
98
+ 先の(1)で挙げたコードでは、mergeの第三引数を、postIdの最大値`maxPostId`にしていましたが、postの個数の上限値`maxPostCount` に変更しました。
99
+
100
+ - **動作確認のサンプル** ???? [tera: 370866 without lodash](https://codepen.io/kilesa/pen/QWMXxxe?editors=0010) @codepen

1

テキスト追加

2021/11/24 21:51

投稿

退会済みユーザー
answer CHANGED
@@ -1,3 +1,18 @@
1
+ 質問にある以下の3点
2
+
3
+ > しかし以下の点が分かりません。
4
+ ・valueには、apiから取得したkeyが対応するpostsのオブジェクトと、postsIdが一致するcommentsの配列を入れ方
5
+ ・50投稿文ループさせる方法がわからない(mapやwhileの指定が分からず)
6
+ ・JSON形式にオブジェクトを入れる方法(JSONファイルを出力するにはnode.jsを使う方法しか出てこず分からない)
7
+
8
+ のうち、はじめの2点を
9
+ (1) postsとcommentsをマージしたオブジェクトを作る
10
+ 3点目を
11
+ (2)ファイルのダウンロード方法
12
+ として回答します。
13
+
14
+ ### (1) postsとcommentsをマージしたオブジェクトを作る
15
+
1
16
  そういうときは、(まずは) [lodash](https://lodash.com/)を使って切り抜けたいです。(※ **備考**も参照ください)
2
17
 
3
18
  ```javascript
@@ -41,4 +56,23 @@
41
56
 
42
57
  **備考:** 最近、lodashは重すぎるといった意見(例: [mizchiさん](https://qiita.com/mizchi/items/af17f45d5653b76f6751))により、現場によっては、lodashの各メソッドを自分で書くこともありますが、その場合は以下が参考になります。
43
58
 
44
- - [You don't (may not) need Lodash/Underscore](https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore) @github.com
59
+ - [You don't (may not) need Lodash/Underscore](https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore) @github.com
60
+
61
+
62
+ ### (2)ファイルのダウンロード方法
63
+
64
+ マージして作成したオブジェクトをJSONファイルにしてダウンロードするには、Blobを使えばよいかと思います。たとえば、前掲の[動作確認のサンプル](https://codepen.io/kilesa/pen/ZEJdxpK?editors=0010) の中で、 Promise.all が成功したときの処理に以下を追加します。
65
+
66
+ ```diff
67
+ Promise.all(fetchers).then(([{ data: posts }, { data: comments }]) => {
68
+ const mergedPosts = merge(posts, comments, 50);
69
+ setPosts(mergedPosts);
70
+
71
+ + // ファイルとしてダウンロード
72
+ + const data = new Blob([JSON.stringify(mergedPosts, null, 4)], {type: 'application/json'});
73
+ + const link = document.createElement('a');
74
+ + link.href = window.URL.createObjectURL(data);
75
+ + link.setAttribute('download', 'mergedPosts.json');
76
+ + link.click();
77
+ });
78
+ ```