はじめに
今回はFlyCode氏が紹介していた、Reactを学ぶ上で知っておくべきJavaScriptの基本概念を紹介します。
具体的なJavaScriptでのコード解説と、Reactではそれがどのように使われるのかを紹介します。
この記事の対象者
- JavaScriptのよく使う基本文法を学びたい人
- Reactの初心者から中級者
この記事の目標
- React開発でよく使われるJavaScriptの文法や処理を理解する
JavaScriptの基礎文法
本記事では下記の7つをピックアップして紹介します
- 三項演算子
- 分割代入
- スプレッド構文
- 配列操作
- アロー関数
- 非同期処理(Async/Await/Promise)
- APIコール
三項演算子
三項演算子はMDNでは下記のように解説されています。
条件 (三項) 演算子は JavaScript では唯一の、3 つのオペランドをとる演算子です。
三項演算子の構文
condition ? exprIfTrue : exprIfFalse
-
condition
は値が条件として使用される式 -
exprIfTrue
はcondition
がtrue
と評価された場合に評価される式 -
exprIfFalse
はcondition
がfalse
と評価された場合に評価される式
JavaScriptコードで具体例を見ていきます。
const flag = true;
const text = flag ? "flagはtrueです" : "flagはfalseです";
console.log(text);
三項演算子で条件して使用される式( flag
)がtrue
なのでconsole.log
では「flagはtrueです」が出力されています。
flag
の値をfalse
に書き換えると「flagはfalseです」が出力されます。
const flag = false;
const text = flag ? "flagはtrueです" : "flagはfalseです";
console.log(text);
三項演算子はReact開発ではコンポーネントの出し分けで使われることが多いです。
const Test: React.FC = () => {
const [isLoading, setIsLoading] = useState<boolean>(true);
return <>{isLoading ? <Loading /> : <Contents />}</>;
};
上記はisLoading
がtrue
だった場合は<Loading />
が表示され、false
だった場合は<Contents />
が表示されます。
今回はisLoading
に初期値としてtrue
が入っているので<Loading />
が表示されます。
分割代入
分割代入はMDNにおいて
分割代入 (Destructuring assignment) 構文は、配列から値を取り出して、あるいはオブジェクトからプロパティを取り出して別個の変数に代入することを可能にする JavaScript の式です。
と書いてあります。
JavaScriptコードで具体的に見ていきます。
let a,b;
[a,b] = [10,20]
console.log(a)
// 10
console.log(b)
// 20
分割構文はReact開発においてprops
の受け渡しの際に使われることがあります。
【propsを受け取る子コンポーネント】
type ContentsProps = {
name: string;
age: number;
};
const Contents: React.FC<ContentsProps> = (props) => {
// propsを分割代入
const { name, age } = props;
return (
<>
<p>名前:{name}</p>
<p>年齢:{age}</p>
</>
);
};
【propsの値を受け渡す親コンポーネント】
const Parent: React.FC = () => {
return <Contents name={"taro"} age={18} />;
};
スプレッド構文
スプレッド構文はMDNにおいて
スプレッド構文 (...) を使うと、配列式や文字列などの反復可能オブジェクトを、0 個以上の引数 (関数呼び出しの場合) や要素 (配列リテラルの場合) を期待された場所で展開したり、オブジェクト式を、0 個以上のキーと値の組 (オブジェクトリテラルの場合) を期待された場所で展開したりすることができます。
と記載されています。
文章だけだとわかりにくいので、具体的なJavaScriptコードを見ていきます。
const array = [1, 2, 3];
// コピーの作成
const copy_array = [...array]; // => [1, 2, 3]
// 要素を追加し新しい配列を生成
const new_array = [...array, 4, 5]; // => [1, 2, 3 ,4, 5]
// 二つの配列をマージする
const merge_array = [...array, ...new_array]; // => [1 ,2 , 3 , 1, 2, 3 ,4, 5]
スプレッド構文はReact開発においては配列やオブジェクトの`state``更新で使われます。
const [fruits, setFruits] = useState<string[]>([
"りんご",
"みかん",
"ぶどう",
]);
// イチゴを追加
const addStrawberry = () => {
const copy = [...fruits];
copy.push("いちご");
setFruits(copy);
};
return (
<>
{fruits.map((fruit, index) => (
<p key={index}>{fruit}</p>
))}
<button onClick={addStrawberry}>いちごを追加</button>
</>
);
ボタンをクリックするといちごが増えていることが確認できます。
また、イチゴを追加する処理においてcopyを取ってる理由は下記の記事で詳しく解説しているので参考にしてみてください。
// イチゴを追加
const addStrawberry = () => {
fruits.push("いちご");
setFruits(fruits); // => これだとstateが更新されない
};
配列操作
配列を操作するメソットはmap
、filter
、find
、reduce
などがありますが、今回は個人的にReact開発でよく使っている
- map
- filter
に絞って解説をしていきます。
map
map() メソッドは、与えられた関数を配列のすべての要素に対して呼び出し、その結果からなる新しい配列を生成します。
【各々の配列の値を2倍にする】
const array = [1, 2, 3, 4];
const new_array = array.map((i) => {
return i * 2;
});
console.log(new_array); // => [2,4,6,8]
Reactにおいてmap
はJSX内でリストをループする際に使われることが多いです。
const [fruits, setFruits] = useState<string[]>([
"りんご",
"みかん",
"ぶどう",
]);
return (
<>
{fruits.map((fruit, index) => (
<p key={index}>{fruit}</p>
))}
</>
);
他にもAPI等で受け取ったレスポンスデータから必要なデータのみを抽出する場合に使うこともあります。
// APIコール等のレスポンスデータ
const responseDate = [
{ id: 1, name: "suzuki", age: 15 },
{ id: 2, name: "satou", age: 20 },
{ id: 3, name: "itou", age: 33 },
];
// レスポンスデータからidとnameのみ抽出
const result = responseDate.map((i) => {
return {
id: i.id,
name: i.name,
};
});
filter
filter
メソットは下記のように解説されています。
filter() メソッドは、この配列の中から、提供された関数で実装されたテストに合格した要素のみを抽出したシャローコピーを作成します。
【wordsの中から6文字より大きいのものだけを抽出】
const words = [
"spray",
"limit",
"elite",
"exuberant",
"destruction",
"present",
];
const result = words.filter((word) => word.length > 6);
console.log(result);
filter
に関しては検索処理やオブジェクト配列の中から条件に合ったものを抽出するときに利用されます。
【usersの中から管理者権限(admin)を持つuserのみ抽出】
const users = [
{
id: 1,
name: "tanaka",
admin: false,
},
{
id: 2,
name: "takahashi",
admin: true,
},
{
id: 3,
name: "matuda",
admin: false,
},
{
id: 4,
name: "okamoto",
admin: true,
},
];
const admin_users = users.filter((i) => i.admin);
console.log(admin_users);
アロー関数
アロー関数はJavaScriptにおいて関数を作成する方法の一つです。
アロー関数の構文は下記のようになっています。
(引数) => {
// 処理
};
従来の関数をアロー関数に直してみます。
// 従来の関数
function (a, b){
return a + b + 100;
}
// アロー関数
(a, b) => a + b + 100;
アロー関数を使うメリットについては下記の記事で詳しく解説されているので、ぜひ参考にしてみてください。
非同期処理
非同期処理はMDNでは下記のように解説されています。
非同期プログラミングは、長く続く可能性のあるタスクを開始しても、そのタスクが完了するまで待つのではなく、そのタスクの実行中も他のイベントに応答できるようにする技術です。タスクが完了すると、プログラムはその結果を表示します。
具体例を用いて噛み砕いて解説をします。
【同期処理(コードを書いた順番に処理が実行される)】
let t = "初期値";
console.log(t); // => "初期値"と出力
t = "更新";
console.log(t); // => "更新"と出力
同期処理ではコードを書いた順番で処理が実行されていることが確認できます。
【非同期処理(コードを書いた順番に処理が実行されない)】
let t = "0秒";
console.log(t);
setTimeout(() => {
t = "2秒経過しました";
}, 2000);
console.log(t);
setTimeout
内で2000ミリ秒(2秒)経過する前(処理を待たず)に次のconsole.log(t)
の処理が発生しているのでどちらも"0"秒のままになっています。
このように処理に待ち時間が発生し、かつ処理によって得られる値を利用したい場合、このままだと期待通りの結果を得ることができません。
下記を使うことで上記の処理を行うことができます。
- Promise
- async/await
Promise
PromiseはMDNでは下記のように解説されています。
Promise オブジェクトは、非同期処理の完了 (もしくは失敗) の結果およびその結果の値を表します。
具体的にコードで解説をしてきます。
-
new Promise
でインスタンス化する - インスタンスの中の引数にコールバック関数を渡す(非同期処理)
-
resolve()
が呼ばれた後にthen
の中のコールバック処理が呼ばれる
let t = "0秒";
console.log(t);
new Promise((resolve) => {
setTimeout(() => {
t = "2秒";
resolve(t);
}, 2000);
}).then((t) => {
console.log(t);
});
このようにsetTimeout
の処理を待った後にconsole.log(t)
が呼び出されているので期待通りの結果になっていることが確認できます。
なおPromise
についてのより詳しい解説はこの記事がわかりやすいので、より深堀したいという方は参考にしてみてください。
async/await
async/await
を利用することでPromise
で書いた処理よりも簡潔に非同期処理を書くことができます。
async/await
についてはMDNで下記のように解説されています。
非同期関数は async キーワードで宣言され、その中で await キーワードを使うことができます。 async および await キーワードを使用することで、プロミスベースの非同期の動作を、プロミスチェーンを明示的に構成する必要なく、よりすっきりとした方法で書くことができます。
-
Promise
の中のコールバック関数をアロー関数として定義 -
async
をアロー関数の前に付与 -
await
を非同期処理の前に付与する - 結果として入ってくる値を
result
に入れる
let t = "0秒";
const timer = async () => {
const result = await new Promise((resolve) => {
setTimeout(() => {
t = "2秒";
resolve(t);
}, 2000);
});
console.log(result);
};
timer();
これによってthen
を書かずに先ほどと同じ処理が行われていることが確認できます。
async/await
についてより詳しく知りたい人は下記の記事を参考にしてみてください。
APIコール
最後にJavaScriptの開発で必須項目でもあるAPI通信について解説をします。
クライアントとサーバー間のデータ通信について
まずクライアントサイドとサーバーサイドの通信について簡単に解説します。
- クライアント(JavaScript等)からほしい情報をサーバーにリクエスト
- サーバー(RubyやPHP等)はリクエストを受けデータをレスポンス
- レスポンス(HTMLやJSON形式等)をクライアント側(画面)で表示
REST API
REST APIはリソースごとにURLのパスが準備されています。
リクエスト送信時のメソット(GET,POST,PUT,DLETE)を変えて同じリソースにリクエストを行うことで処理が実行されます。
今回は先ほど紹介した下記の部分においてデータを実際に取得する処理を書いてきます。
axiosを使ってAPIコール
APIコールをするためにJavaScriptではaxios
というライブラリが用意されています。
axios
を使うことで、GETやPOSTのHTTPリクエストを使ってサーバーからデータの取得、サーバーへデータ送信、追加、更新、削除を行うことができます。
JSONPlaceholderを使って具体的にデータを取得する処理を書いてみます。
【JSONPlaceholderからusers情報をGETするリクエストを送る】
const getUsers = async () => {
const res = await axios.get("https://jsonplaceholder.typicode.com/users");
console.log(res.data);
};
getUsers();
APIコールは外部との通信が走るので先ほど紹介した非同期処理のasync/await
を利用しています。
下記のようにusers
情報が返ってきていることが確認できます。
またReactにおけるAPIコールは副作用なのでuseEffect
内で呼び出されることが多いです。(useAsync
等もある)
const [user, setUsers] = useState<User>([]);
useEffect(() => {
const getUsers = async () => {
const res = await axios.get("https://jsonplaceholder.typicode.com/users");
setUsers(res.data);
};
getUsers();
}, []);
console.log(user);
なぜuseEffect
の中で呼び出されるかについての詳しい解説は下記の記事でおこなっているので参考にしてみてください。
最後に
いかがだったでしょうか。
今回はReactを学ぶ上で知っておくべきJavaScriptの基本概念についてまとめました。
他にもReact関連の記事を出しているので、合わせて読んでいただけると嬉しいです。