はじめに
最近、ひょんなことから初学者向けのReactアプリをレベル別に10個くらい開発しながら、ハンズオンで学べる教材的なものを作成する機会があり、それを実施する前に最低限理解していたら学習がスムーズに進むだろうと思われるものをまとめました。
また、予習編としてReact専用で使用されるものも簡単に紹介します。
ちなみに、すでに「基本編くらいわかるわ!」って方は予習編はみなくていいので、以下のリファレンスのチュートリアルをやっちゃってください。Udemyなんかでもいいと思いますのでどんどん手を動かすフェーズに入っていきましょう。
また、JavaScriptは全くわからんという方は、こちらの実際にアニメーションや動くものを作りながら学べる教材を作成しましたので、是非、使ってください。もちろん無料です
基本編(JavaScript)
-
map
メソッド- 配列内の全ての要素に対して関数を適用し、新しい配列を作成します。
const items = ['apple', 'banana', 'cherry']; const listItems = items.map(item => <li key={item}>{item}</li>);
-
items
配列の各要素を<li>
タグで囲み、listItems
という新しい配列を作成します。 - 特にこのmap()はアホみたいにReactでは出現しますので、もう覚えちゃいましょう。一番出てくるのは以下のような形です。
const todos = [ { id: 1, text: 'Learn JavaScript', completed: false }, { id: 2, text: 'Build a Todo App', completed: false }, { id: 3, text: 'Master React', completed: false } ]; function TodoList() { return ( <ul className=''> // スタイリングは省略 {todos.map((todo) => ( <li key={todo.id}> {todo.text} </li> ))} </ul> ); } export default TodoList;
-
filter
メソッド- 配列内の要素をフィルタリングして、新しい配列を作成します。
- こちらもよく使用されます。map()と形が似ていて初学者の方は混乱するかもしれませんが違いを理解しておきましょう。
const numbers = [1, 2, 3, 4, 5]; const evenNumbers = numbers.filter(number => number % 2 === 0);
-
numbers
配列から偶数だけを含む新しい配列evenNumbers
を作成します。
例えばTodoなんかの削除機能がわかりやすい例かと思います。以下のように、対象のtodoのidと一致しないidをフィルタリングしてあげれば引数で渡されたidのtodoは除外された配列が作成されて、delete機能が完成します。
const [todo, setTodo] = useState<{ text: string; isComplete: boolean }[]>([]); // 省略 const deleteTodo = (index: number) => { setTodo((prev) => prev.filter((_, i) => i !== index)); };
-
スプレッド構文
- 配列やオブジェクトを展開してコピーを作成します。
const obj1 = { a: 1, b: 2 }; const obj2 = { ...obj1, c: 3 };
-
obj1
の全てのプロパティをコピーし、さらにc: 3
を追加した新しいオブジェクトobj2
を作成します。
-
分割代入
- オブジェクトや配列から特定のプロパティや要素を抽出して変数に代入します。
const user = { name: 'John', age: 30 }; const { name, age } = user;
-
user
オブジェクトからname
とage
を取り出して、それぞれ変数name
とage
に代入します。
-
アロー関数
- 簡潔な関数定義の方法です。
const add = (a, b) => a + b;
-
a
とb
を引数として受け取り、それらの和を返す関数add
を定義します。
-
テンプレートリテラル
- 文字列を簡単に組み立てる方法です。
const name = 'John'; const greeting = `Hello, ${name}!`;
- 文字列内に変数
name
の値を埋め込んで、Hello, John!
という文字列を作成します。
-
オプショナルチェイニング
- 存在しないプロパティにアクセスしてもエラーにならないようにする構文です。
const user = { address: { city: 'Tokyo' } }; const city = user?.address?.city;
-
user
オブジェクトのaddress
プロパティが存在する場合にcity
にアクセスします。
-
Null合体演算子
- 左側の値が
null
またはundefined
の場合に右側の値を返します。
const name = user.name ?? 'Guest';
-
user.name
がnull
またはundefined
の場合、'Guest'
を返します。
- 左側の値が
-
find
メソッド- 配列内の条件に一致する最初の要素を返します。
const users = [{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }]; const user = users.find(user => user.id === 1);
-
users
配列からid
が1の最初のユーザーを見つけます。
-
reduce
メソッド- 配列を一つの値にまとめます。
const numbers = [1, 2, 3, 4]; const sum = numbers.reduce((total, number) => total + number, 0);
-
numbers
配列の全ての要素を合計してsum
を計算します。
-
プロパティショートハンド
- オブジェクトリテラルの簡潔な記述方法です。
const name = 'Alice'; const age = 30; const person = { name: name, // この左辺と右辺が同じ場合は省略可能 age: age }; console.log(person); // { name: 'Alice', age: 30 } // 省略した形 const name = 'Alice'; const age = 30; const person = { name, age }; console.log(person); // { name: 'Alice', age: 30 }
-
name
とage
をそのままオブジェクトのプロパティとして使用します。
-
論理AND (&&) 演算子
- 条件が真の場合にのみ要素を表示します。
const isLoggedIn = true; return ( <div> {isLoggedIn && <button>Logout</button>} </div> );
-
isLoggedIn
がtrue
の場合にのみ<button>Logout</button>
を表示します。
-
条件付きレンダリング(三項演算子)
- 条件によって表示内容を切り替えます。
const isLoggedIn = true; return ( <div> {isLoggedIn ? <button>Logout</button> : <button>Login</button>} </div> );
-
isLoggedIn
がtrue
の場合は<button>Logout</button>
を表示し、false
の場合は<button>Login</button>
を表示します。
また、以下のように動的にスタイリングするためにもよく使用されます。
ボタンの有効/無効状態のスタイリング
import { useState } from 'react';
import { Button } from '@chakra-ui/react';
const DynamicButton = () => {
const [isDisabled, setIsDisabled] = useState(true);
return (
<Button
onClick={() => setIsDisabled(!isDisabled)}
bg={isDisabled ? 'gray.400' : 'blue.500'}
color={isDisabled ? 'white' : 'black'}
cursor={isDisabled ? 'not-allowed' : 'pointer'}
disabled={isDisabled}
>
{isDisabled ? 'Disabled' : 'Enabled'}
</Button>
);
};
export default DynamicButton;
アラートメッセージの種類に基づくスタイリング
import { Box } from '@chakra-ui/react';
const AlertMessage = ({ type, message }) => {
return (
<Box
p={4}
bg={
type === 'success'
? 'green.200'
: type === 'error'
? 'red.200'
: 'gray.200'
}
color={
type === 'success'
? 'green.800'
: type === 'error'
? 'red.800'
: 'gray.800'
}
>
{message}
</Box>
);
};
export default AlertMessage;
- 条件Aならこのスタイルをあてる、そうでなければBのスタイルをあてるといった具合です。
さらに詳しく知りたい方はこちらをどうぞ
破壊的メソッドと非破壊的メソッドを理解する
JavaScriptにおけるよく使用されるメソッドを、破壊的メソッドと非破壊的メソッドに分類します。なあなあにしがちですが、かなり重要な部分なので簡単に記載しておきます。
詳しくはこちらに記載しましたのでご覧ください
破壊的メソッド (Destructive Methods)
破壊的メソッドは、元の配列やオブジェクトを直接変更するメソッドです。
配列の破壊的メソッド
-
push()
: 配列の末尾に1つ以上の要素を追加します。 -
pop()
: 配列の末尾の要素を削除します。 -
shift()
: 配列の先頭の要素を削除します。 -
unshift()
: 配列の先頭に1つ以上の要素を追加します。 -
splice()
: 配列の指定された部分に要素を追加、削除、または置換します。 -
sort()
: 配列をソートします。 -
reverse()
: 配列の要素を反転させます。 -
fill()
: 配列の要素を指定した値で埋めます。
オブジェクトの破壊的メソッド
-
Object.assign()
: オブジェクトのプロパティを別のオブジェクトにコピーするためのメソッドです。複数のソースオブジェクトからターゲットオブジェクトにプロパティをコピーすることができます。const target = { a: 1, b: 2 }; const source = { b: 4, c: 5 }; const returnedTarget = Object.assign(target, source); console.log(target); // { a: 1, b: 4, c: 5 } console.log(returnedTarget); // { a: 1, b: 4, c: 5 }
-
Object.freeze()
: オブジェクトを凍結し、そのプロパティを変更できないようにするためのメソッドです。凍結されたオブジェクトは、プロパティの追加、削除、変更ができなくなります。
※元オブジェクトの中身は変わりませんが、状態が変わってしまう(追加、削除などができなくなる)ので破壊的とみなされます。const obj = { prop: 42 }; Object.freeze(obj); obj.prop = 33; // この変更は無視されます obj.newProp = 'new'; // この追加も無視されます delete obj.prop; // この削除も無視されます console.log(obj.prop); // 42 console.log(obj.newProp); // undefined
-
Object.seal()
: オブジェクトをシール(封印)し、既存のプロパティを変更可能に保ちながら、新しいプロパティの追加や既存プロパティの削除を禁止するメソッドです。これにより、オブジェクトの形状が固定され、追加や削除による変更が防止されますが、プロパティの値は変更できます。const obj = { prop: 42 }; Object.seal(obj); obj.prop = 33; // プロパティの値は変更可能 obj.newProp = 'new'; // 新しいプロパティの追加は無視される delete obj.prop; // プロパティの削除は無視される console.log(obj.prop); // 33 console.log(obj.newProp); // undefined
破壊的な演算子
-
delete
: オブジェクトからプロパティを削除します。
非破壊的メソッド (Non-Destructive Methods)
非破壊的メソッドは、元の配列やオブジェクトを変更せず、新しい配列やオブジェクトを返すメソッドです。
配列の非破壊的メソッド
-
concat()
: 2つ以上の配列を結合します。 -
slice()
: 配列の一部を新しい配列として抽出します。 -
map()
: 配列の各要素に対して関数を適用し、新しい配列を返します。 -
filter()
: 条件を満たす要素を含む新しい配列を返します。 -
reduce()
: 配列を1つの値にまとめます。 -
reduceRight()
: 配列を右から左に1つの値にまとめます。 -
find()
: 条件を満たす最初の要素を返します。 -
findIndex()
: 条件を満たす最初の要素のインデックスを返します。 -
some()
: 少なくとも1つの要素が条件を満たすかをチェックします。 -
every()
: 全ての要素が条件を満たすかをチェックします。 -
includes()
: 配列が特定の要素を含むかをチェックします。 -
indexOf()
: 配列内の特定の要素の最初のインデックスを返します。 -
lastIndexOf()
: 配列内の特定の要素の最後のインデックスを返します. -
join()
: 配列の全要素を文字列として結合します.
オブジェクトの非破壊的メソッド
-
Object.keys()
: オブジェクトのキーの配列を返します。 -
Object.values()
: オブジェクトの値の配列を返します。 -
Object.entries()
: オブジェクトのキーと値のペアの配列を返します。
予習編(React専用のHooksとTailwind CSS)
ちなみによくHook(フック)という言葉が用いられるのですが、これは特定のイベントやライフサイクルのタイミングで追加の処理を挿入するための仕組みのことです。
React初学者の方はここからは「こんなものがあるんだなぁ」くらいでいいと思います。
解説を最低限にしてますので、余裕があれば各Hooksを調べてみましょう。
-
useState
フック- コンポーネント内で状態を管理するためのフックです。
const [count, setCount] = useState(0);
-
count
という状態変数を宣言し、初期値を0に設定します。setCount
はcount
を更新するための関数です。
-
useEffect
フック- 副作用(データのフェッチやDOMの操作など)を実行するためのフックです。
useEffect(() => { // コンポーネントがマウントされた時の処理 return () => { // クリーンアップ処理 }; }, []);
- 第二引数を使用して(ここでは[]のこと)、コンポーネントが初めて表示された時や特定の値が変化した時に実行される処理を記述します。
-
useRef
フック- DOM要素や値を保持するためのフックです。
const inputRef = useRef(null); useEffect(() => { inputRef.current.focus(); }, []);
-
inputRef
を使って入力フィールドを参照し、コンポーネントが表示された時にフォーカスを当てます。
例えば、textareaに対してuseRefを使用して、入力された値を取得したりできます。
const SimpleTodo: NextPage = () => {
// 省略
const textAreaRef = useRef<HTMLTextAreaElement>(null);
return (
<textarea
ref={textAreaRef}
placeholder="useRefを使用したTodoアプリ" />
)
}
// 取得方法
const textAreaValue = textAreaRef.current?.value;
useRefについての詳細を知りたい方はこちらからどうぞ
4.useContext
フック
- Reactアプリケーション全体でデータをグローバルに共有するためフックです。
const MyContext = CreateContext(); const value = useContext(MyContext);
-
MyContext
から値を取得します。
-
5.useMemo
フック
- レンダー間で計算結果をキャッシュ(メモ化)するためのフックです。
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
-
a
とb
が変わらない限り、computeExpensiveValue
の結果を再計算せずに返します。
-
6.useCallback
フック
- 関数をメモ化するためのフックです。
const memoizedCallback = useCallback(() => { doSomething(a, b); }, [a, b]);
-
a
とb
が変わらない限り、同じ関数インスタンスを返します。
-
7.useState
useEffect
使用したfetch API
- ネットワークリクエストを送信してデータを取得するためのAPIです。
const DataFetchingComponent = () => { const [data, setData] = useState(null); // useState フックを使用して state を定義 useEffect(() => { fetch('https://api.example.com/data') .then(response => response.json()) .then(data => setData(data)); // 取得したデータを state にセット }, []); // 空の依存配列により、コンポーネントの初回マウント時のみ実行 return ( // 省略 ); }
- APIからデータを取得して
setData
で状態を更新します。
- APIからデータを取得して
注意点
「useEffect
, useMemo
, useCallback
の第2引数が変化しない=実行されない」ではないのでご注意ください。
例えばコンポーネントの状態が変わったり、親コンポーネントが再レンダリングされたりすると、Reactのスケジューリングの関係で依存配列が変わっていなくても再実行される場合があります。他にも要因はありますが頭の片隅に入れておきましょう。
Tailwind CSSを使用したスタイリング
Reactでの開発で大活躍するのはこのTailwind CSSです。
簡単に言うとHTMLタグ内に直接、しかも短縮した形で記述していく形になります。
単純なスタイリングだけでも効率が良くなるのですが、その他にもアニメーションや動的なスタイリング、動的なレスポンシブ対応など可能性は無限大です。
以下のドキュメントは必ず目を通しておきましょう
Tailwind CSSの能力を爆上げする小技集 Best 3
おススメの書籍
最近はリスキリングサービスの発展で動画学習が主体になっていますが、手元に一冊あると重宝する位置づけのものを紹介します。
独習JavaScript
https://amzn.to/3KkBWEG
この書籍のいいところは、「初心者はスキップしていいところ」「レベルアップしたい人用」 などが項目に記載してあって、さらにJSのメカニズム的な部分から丁寧に説明されてあるので、辞書的な使い方でもいいですし、ゆっくりわからないところはGPTに聞きながら独習するという感じでもかなり勉強になります。
【補足】たまに使うメソッドを紹介する(初心者スルーしてOK)
flatMap()
flatMap()
は配列内の各要素に対して指定された関数を適用し、その結果をフラットな配列として結合します。これはmap()
とflat()
を一度に行うような動作をします。
基本的な使い方
const array = [1, 2, 3, 4];
const result = array.flatMap(x => [x, x * 2]);
console.log(result); // [1, 2, 2, 4, 3, 6, 4, 8]
この例では、元の配列の各要素に対して、要素自身とその2倍の値を持つ配列を返し、その結果をフラットな配列として結合しています。
使い方の例
-
ネストされた配列のフラット化:
flatMap()
は、ネストされた配列を1段階フラットにするのに便利です。const nestedArray = [[1], [2], [3], [4]]; const flatArray = nestedArray.flatMap(x => x); console.log(flatArray); // [1, 2, 3, 4]
-
フィルタリングとマッピングの組み合わせ:
flatMap()
を使うと、フィルタリングとマッピングを一度に行うことができます。const numbers = [1, 2, 3, 4, 5]; const evenSquares = numbers.flatMap(x => x % 2 === 0 ? [x * x] : []); console.log(evenSquares); // [4, 16]
この例では、偶数の要素だけを2乗して返し、フラットな配列にしています。
-
複雑な変換:
flatMap()
を使って、各要素をより複雑な構造に変換することもできます。const sentences = ["this is a sentence", "another sentence"]; const words = sentences.flatMap(sentence => sentence.split(" ")); console.log(words); // ["this", "is", "a", "sentence", "another", "sentence"]
この例では、文を単語に分割し、すべての単語を一つのフラットな配列にしています。
参考資料
終わりに
全て覚える必要はありませんが、それぞれの特徴を理解してどういう動きをするかだけは押さえておきましょう。
特に破壊的メソッドと非破壊的メソッドに関しては、「元のオブジェクトそのものの状態や性質を変更してしまう」ものとそうでないものがあるという認識で頭に入れておけばいいと思います。
それぞれの理解ができたらGPT先生に聞いて、実際にそのメソッドや構文を利用した実用例を出してもらって理解を深めるとさらにいいと思います。