こんにちはカレイドです。
前回、前々回とJavaScriptの基礎部分についてみてきました。
【プログラミング】HTML/CSSを学んだら次はJavaScript!最低限の知識を紹介します
JavaScriptからReactへ。map関数,三項演算子、論理演算子【プログラミング】
今回は基礎部分の最後として次のようなものを学んでいきます。
- 特定の条件にマッチするものを残すfilter関数
- オブジェクトや配列をより便利に扱うスプレッド演算子、分割代入
- サーバーとのやりとりなどの非同期処理を扱うasync/await構文
ここまでくるとなるほどそんな感じなのかと思ってもらえればOKなので気負わずにいきましょう。
前回の部分を少し軽く触れながら復習も兼ねていこうと思います。
分割代入
まずは分割代入です。当たり前のようにコーディング中に使われるので知っておきましょう。
この書き方ができると自分が書くコードの分量が減るし、見栄えも良くなるので大変重宝するようになると思います。
const profile={
username:"fugafuga",
email:"hogehoge",
password:"piyopiyo",
}
const { username, password }=profile
console.log( username ) // "fugafuga"
console.log( password ) // "piyopiyo"
基本的なオブジェクトの分割代入ですね。必要なものだけ { } の中に書いてあげるだけで必要なものだけを取り出すことができます。
普通なら profile.usernameというようにアクセスするところを省略できるのでコードが見やすくなる利点がありますね。
また { } の中身についてですが、当然ながらプロパティの順番は関係ありません。好きなように埋めてあげればOKです。
続いては配列の分割代入を見て行きます。
const [color1, color2] = ["red", "blue"];
console.log(color1,color2); // "red" "blue"
こちらは右側に定義されている配列のvalueを左側の変数に代入しています。
オブジェクトの分割代入と異なり順番通りに格納されるので間違えないようにしましょう。
複数ある場合はスキップして値を引っ張ることも可能です。
const [color1,,color3]=["red","blue","yellow"]
console.log(color1,color3) // "red" "yellow"
私だけかもしれませんがこういう使い方はあんまりしたことはないです。知っておくと良いぐらいで覚えてもらえるといいです。
スプレッド演算子
どちらかというとこちらの方が便利かつ、知っていないと困るレベルです。
スプレッドは広げるという意味をもちます。つまり、配列の中身やオブジェクトの中身を広げる働きを持っています。
ちょっと上と似ていますが、数の指定は出来ず中身全てを広げます。
使い方は簡単で配列やオブジェクトの先頭に ...
を3つつけてあげるだけでOKです。
そしてどのような時に使うかというと配列であればこのように配列の中で使ってあげると新たに前や後ろに要素を追加できたりします。
const color = ["red", "blue"];
const newColor = [...color, "special"]; // ["red", "blue","special",]
const newColor2 = ["special", ...color]; //["special", "red", "blue"]
おっしゃる通りその通りです。でもpushと大きく違うのは元の配列の中身に変更を加えないというところです。
ここでは新たにnewColorと呼ばれる新しい変数を作るだけでcolor自体の中身は変更されていません。
ここが一番重要な点です。
オブジェクトは少し挙動が変わって同じプロパティに対しては上書き処理が施されます。
異なるプロパティは同じように足し算がされます。
const profile = {
username: "hoge",
email: "fuga"
};
const newProfile = {
...profile,
imageUrl: "http://ajergoierg"
};
console.log(newProfile); //{email: "fuga, imageUrl: "http://ajergoierg" ,username: "hoge"}
const newProfile1 = {
...profile,
username: "kaleido"
};
console.log(newProfile1); //{email: "fuga ,username: "kaleido"} 一番よく使う
const newProfile2 = {
username: "kaleido",
...profile
};
console.log(newProfile1); //{email: "fuga ,username: "hoge"}
いくつかのパターンを示してみました。一番上は新しいプロパティを足し算する場合ですね。
次は一番よく使うパターンです。デフォルト値だった状態から新たに値を更新する場合、先ほども行ったように profile.username="kaleido"
では直接変更されてしまうのであまりよろしくありません。僕の感覚としては変更することは可能ですが、あまり見栄えは良くないです。
新しい変数を作ってしまった方がとてもわかりやすくスマートです。
そして最後のパターンは何も変化していないですね。先にusernameを書いてしまうとオブジェクトは後ろのprofileのusernameで上書きするので結果的には意味のない変更になってしまうので注意しましょう。
今日のReact 非同期処理とfilterを使ってみる。
さて、今度は普段のReactで書いているようにみてみましょう。ところどころ難しい部分も出てきますが、感覚を掴んでもらえればOKです。
前回までの記事で説明した内容も入っていますのであやふやな人はしっかり確認しておきましょうね。
非同期処理特有のテクニックも頑張って理解していただきます。
JavaScriptからReactへ。map関数,三項演算子、論理演算子【プログラミング】
React特有の表現は次回に回そうと思いますのでなんとなくでOKです。
ここで紹介したものはjsonPlaceholder
とよばれるサイトがあってそこの偽のjsonデータを利用して画面表示まで行なっているプログラムになります。
実際のWebアプリもどこかのサーバーからユーザー情報なり商品データなどを格納しているサーバーにリクエストを送ってもらってデータを返してもらうという処理を行なっています。
今回はその一連の流れの感覚を実際の関数や構文をみながら押さえていきましょう。
useState, useEffect, async/await
まずは
const [posts, setPosts] = React.useState();
ですね。
先ほど説明した分割代入をしていることに気がつきましたか?。
React.useState()
は特有な関数なので詳細な説明は省きますが 返り値に配列を返します。その値の一つ目には自分が状態を保持しておきたいもの、二つ目にそれを変更するための関数を返します。ここが少し難しそうですね。
Reactでは画面を表示するのにレンダリング(お絵かきだと思ってください)する必要があります。それを強制的に作動させるためにsetPostsを使います。単にpostsに再代入しても再度レンダリングがされません。つまり、もう一回絵を書き直してもらわないとみなさんがみている画面には反映してもらえないということです。
まだReactを勉強していない人はとりあえず、一つ目に状態保持したい変数、二つ目にその変数を書き換えてリロードする関数を返すと思ってくれればOKです。
今回なら外部から偽の投稿を取ってきてそれが完了したら値を格納してデータ表示をしているのでposts,とsetPostsという変数を割り当てています。
React.useEffect(() => {
const fetchData = async () => {
const res = await fetch("https://jsonplaceholder.typicode.com/posts");
console.log(res);
const data = await res.json();
console.log(data);
setPosts(data);
};
fetchData();
}, []);
ここが多分一番難しいところですね。これも今回は軽く説明しておきます。
React.useEffect()
ではReact特有の関数で画面にデータをレンダリングする前に先ほど紹介した、偽のデータを置いてくれているサイトへ1度だけリクエストを飛ばしています。
const fetchData = async () => {
const res = await fetch("https://jsonplaceholder.typicode.com/posts");
console.log(res);
const data = await res.json();
console.log(data);
setPosts(data);
};
fetchData();
そしてfetchDataは関数ですね。
ここで今回のメインの一つasync/awaitが登場します。
詳しい概念的な解説をしている解説はたくさんあるのでここではざっくりなイメージとして外部とのやり取りや、時間のかかる処理にはasync/awaitと覚えておけばよいです。
やっていることは一旦Promiseと呼ばれる部分に行なっている処理を退避させておき、終わり次第、値を格納すると思ってください。
使い方は関数の先頭にasyncをつけて非同期処理の部分にawaitをくっつければOKです。初めはどこにつけたらいいかなど間違えることもあると思いますが、これに関してはかなり慣れの部分があります。そして返り値がpromiseかどうかはvscodeを使っている人はマウスオーバーでPrimise<>というような返り値が入っている場合は非同期処理だと思っておけばひとまずはOKです。
ここでは最終的に処理が終わった物を先ほど用意したsetPosts
に格納して値を更新しています。
途中に置いてあるconsole.log(posts)をみていただければ100個ほどデータが格納された配列があることがわかると思います。
filter関数
次はfilter関数をみていこうと思います。
イメージは次のようになるのですが、前者は特定の条件を通過させるイメージ
後者のこちらは特定の条件以外のものを通過させるイメージなのですが、みなさんはfilterのイメージってどっちですかね。私は後者です。
だいたいあるあるパターンは特定のidを持つオブジェクトを取り除いた配列が欲しいとかそんな時ですね。
というわけでそれを行なっている関数が
const filterUserId = (userId, posts) => {
const filteredPosts =
posts &&
posts.filter(post => {
return userId !== post.userId;
});
return filteredPosts;
};
こちらになります。
関数の名前を読んでuserIdをfilterするんだなと想像できたでしょうか。ここからは個人差だとは思いますが基本的にフィルターってその指定したものを取り除いて残りを通過させるっていうイメージじゃないですか?
水の中の不純物を取り除くとかもフィルター使いますよね?
なのでここでのfilterは特定のuserIdを持つpostsを取り除く条件の!==が指定されています。
先ほど言ったようにこの使い方が基本で、指定した条件以外を通過させるパターンで使う場合が多いです。
まずは丁寧に書いたものなのですが、左からきちんと読んで頭でイメージすれば読み解けると思います。前回出てきたposts && となっているのは
postsがundefinedの可能性もあるからですね。前回の記事で説明をしたようにpostsは最初undefinedです。そして非同期で後になってから100個のオブジェクトを持った配列になります。
なので一瞬生まれるundefinedにfilter関数を適用させようとするとエラーがおきます。これを回避するために存在する場合のみにfilterを適用させているというわけですね。
そして、この関数を最大限まで省略するとこうなります。
const filterUserId = (userId, posts) =>
posts && posts.filter(post => userId !== post.userId);
return前に処理がないかつ、return以下が一文でかける場合、{ return }表記を省略してreturn に続く部分をそのまま書くことができます。
これがfilterUserIdの=>に続くreturnと、filter以下に続くreturnを省略してこうなっています。
最初は丁寧に一個一個綺麗に書いていく方がいいと思います。
慣れればこれをみて、なるほどuserIdと対象になるpostsを受けとってpostsがある場合にはfilterをとおしてpostのuserIdと同じuserIdのものを取り除く関数なのかという読み解きができるようになると思います。
今回は
const filteredPosts = filterUserId(1, posts);
としているのでuserIdが1のものを全て取り除いた投稿になっていることが確認できると思います。
スプレット構文の復習
おまけとして新しいpostsを作成してそれを新しい配列として作る部分をいれてみました。
これは先ほどの復習になるので確認してみてください。
const newPosts = {
id: 101,
userId: 7,
title: "This is a new title",
body: "This is a new body"
};
const newFilterdPosts = filteredPosts && [...filteredPosts, newPosts];
view部分
最後ですね。これは前回もみたので軽くですが最後にできたnewFilteredPostsをmapして表示をしようとしています。
そのさいprofileの各値をしようするので先に分割代入でprofileからプロパティを取り出してから表示をしています。
return (
<div className="App">
{newFilterdPosts &&
newFilterdPosts.map(post => {
const { body, id, title, userId } = post;
return (
<div
key={id}
style={{
border: "1px solid black",
margin: "5px"
}}
>
<p>"userId":{userId}</p>
<p style={{ color: "blue" }}>"title":{title}</p>
<p style={{ color: "salmon" }}>"body":{body}</p>
</div>
);
})}
</div>
);
同様にしてここもundefinedが入ってくる可能性が存在するためそのチェックを怠ってはいけませんね。初心者のうちは頻繁にエラーが起きると思いますが、私も最初の時はエラーのオンパレードだったのでその都度undefinedチェック怠っていないかをまず確認してみるといいと思います。
ちなみにTypeScriptとよばれるJSにしっかりと型を定義できるもの使うとこういうミスは無くなりますので頭の片隅に入れておくといいでしょう。最初はJSで動くコードをかけるようにまずは頑張りましょう。
終わりに。 JSの基礎部分は終了。
お疲れ様でした。全3回でしたがほとんどJSで使う構文は紹介したと思います。まだいくつかmapのような構文がありますが頻度は少ないのでいつかのタイミングで勉強したらいいと思います。
ひとまずは全3回の内容をきちんと理解してReactなりVueなりを始めれば多少のギャップは埋められるんじゃないかなーと思います。
それでは次回は本格的なReactでお会いしましょう!