序章
このチュートリアルでは、Reactフックを使用してカウントダウンタイマーを作成し、Reactコンポーネントの状態を更新して副作用を管理します。
Reactフックを使用すると、よりクリーンなコード、コンポーネント間で再利用可能なロジックを作成し、クラスなしで状態を更新できます。
カウントダウンタイマーは一般的なUIコンポーネントです。 ユーザーは、何かをしている時間や、イベントが発生するまでの時間をユーザーに伝えることができます。 このチュートリアルでカウントダウンするイベントは、DigitalOceanのHacktoberfestです。
このチュートリアルの終わりまでに、ReactのuseState()およびuseEffect()フックを使用した機能的で再利用可能なカウントダウンタイマーができあがります。
前提条件
このガイドを開始する前に、次のものが必要です。
- Node.jsを実行する開発環境が必要になります。 これをmacOSまたはUbuntu18.04にインストールするには、Node.jsをインストールしてmacOSにローカル開発環境を作成する方法またはのPPAを使用したインストール]セクションの手順に従います。 Ubuntu18.04にNode.jsをインストールする方法。
- このチュートリアルでは、 Create ReactAppを使用してアプリを作成します。 Create React Appを使用してアプリケーションをインストールする手順については、 CreateReactAppを使用してReactプロジェクトを設定する方法を参照してください。
- また、 JavaScriptでコーディングする方法にあるJavaScriptの基本的な知識と、HTMLおよびCSSの基本的な知識も必要です。 HTMLとCSSの便利なリソースは、 Mozilla DeveloperNetworkです。
このチュートリアルは、Node.js v16.13.1、npm v8.2.0、およびreactv17.0.2で検証されました。
ステップ1—空のプロジェクトを作成する
このステップでは、 Create ReactAppを使用して新しいプロジェクトを作成します。 次に、プロジェクトをブートストラップするときにインストールされるサンプルプロジェクトと関連ファイルを削除します。
まず、新しいプロジェクトを作成します。 ターミナルで次のスクリプトを実行し、create-react-appを使用して新しいプロジェクトをインストールします。
npx create-react-app react-hooks-timer
プロジェクトが終了したら、次のディレクトリに移動します。
cd react-hooks-timer
新しいターミナルタブまたはウィンドウで、 CreateReactApp開始スクリプトを使用してプロジェクトを開始します。 ブラウザは変更時に自動更新されるため、作業中はこのスクリプトを実行したままにします。
npm start
ローカルで実行されているサーバーを取得します。 プロジェクトがブラウザウィンドウで開かなかった場合は、http://localhost:3000/で開くことができます。 これをリモートサーバーから実行している場合、アドレスはhttp://your_server_ip:3000になります。
ブラウザには、CreateReactAppによって生成されたReactアプリケーションが読み込まれます。
新しいカスタムコンポーネントのセットを作成するので、空のプロジェクトを作成できるように、ボイラープレートコードをクリアすることから始める必要があります。
まず、テキストエディタでsrc/App.jsを開きます。 これは、ページに挿入されるルートコンポーネントです。 すべてのコンポーネントはここから始まります。 App.jsの詳細については、 Create ReactAppを使用してReactプロジェクトをセットアップする方法を参照してください。
次のコマンドでsrc/App.jsを開きます。
nano src/App.js
次のようなファイルが表示されます。
react-hooks-timer / src / App.js
import React from 'react';
import logo from './logo.svg';
import './App.css';
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;
次に、returnステートメントのすべてを置き換えて、<div>タグのセットを返します。 これにより、何も返さない有効なページが表示されます。 最終的なコードは次のようになります。
react-hooks-timer / src / App.js
import React from 'react';
import logo from './logo.svg';
import './App.css';
function App() {
return (
<div>
</div>
)
}
export default App;
次に、ロゴを削除します。 import logo from './logo.svg';の行を削除します。
テキストエディタを保存して終了します。
最後に、このアプリケーションでは使用しないため、ロゴを削除します。 混乱を避けるために、作業中に未使用のファイルを削除することをお勧めします。
ターミナルウィンドウで、次のコマンドを入力します。
rm src/logo.svg
プロジェクトが設定されたので、最初のコンポーネントを作成できます。
ステップ2—残り時間を計算する
このステップでは、現在の日付からHacktoberfestの初日までの残り時間を計算する関数を作成します。
まず、calculateTimeLeftという関数を設定します。
react-hooks-timer / src / App.js
// ...
const calculateTimeLeft = () => {
};
// ...
次に、関数内で、JavaScript Dateオブジェクトを使用して、現在のyearを検索します。
JavaScriptdateメソッドDate.getFullYear()に設定されるyearという変数を作成します。
calculateTimeLeft関数内に次のコードを追加します。
react-hooks-timer / src / App.js
// ...
const calculateTimeLeft = () => {
let year = new Date().getFullYear();
}
// ...
注: JavaScript Dateオブジェクトを使用して、日付と時刻を操作できます。
Date.getFullYear()メソッドは今年を取得します。
これで、この変数を使用して、現在の日付とHacktoberfestの初日の差を計算できます。
calculateTimeLeft関数内に、differenceという新しい変数を追加します。 次のコードを使用して、新しいDateオブジェクトと等しくなるように設定します。
react-hooks-timer / src / App.js
// ...
const calculateTimeLeft = () => {
let year = new Date().getFullYear();
const difference = +new Date(`10/01/${year}`) - +new Date();
}
// ...
新しいDateオブジェクトの前の+は、JavaScriptにオブジェクトを整数としてキャストするように指示する省略形です。これにより、エポックからのマイクロ秒で表されるオブジェクトのUnixタイムスタンプが得られます。
注:このチュートリアルでは、カウントダウンする日付が将来設定されていることを確認してください。設定されていない場合、エラーが発生します。
コードを再利用可能に保つには、 JavaScript Template Literal を使用し、Hacktoberfestの月日とともにyear変数を追加します。 Hacktoberfestは毎年10月1日に始まります。 ハードコードされた年の代わりにyear変数を使用すると、常に現在の年になります。
カウントダウンタイマーが切れるまでの合計ミリ秒数を計算したので、ミリ秒数をより親しみやすく人間が読める形式に変換する必要があります。
ステップ3—日、時間、分、秒にフォーマットする
このステップでは、timeLeftという空のオブジェクトを作成し、ifステートメントを使用して残り時間があるかどうかを確認し、数学を使用して時間、分、秒の合計数を計算しますおよびモジュラス(%)演算子。 最後に、timeLeftを返します。
まず、timeLeftという空のオブジェクトを作成します。このオブジェクトには、ifステートメントに日、時間、分、秒が入力されます。
calculateTimeLeft関数内に次のコードを追加します。
react-hooks-timer / src / App.js
// ...
const calculateTimeLeft = () => {
let year = new Date().getFullYear();
let difference = +new Date(`10/01/${year}`) - +new Date();
let timeLeft = {};
}
// ...
次に、difference変数を比較して0より大きいかどうかを確認するifステートメントを作成します。
calculateTimeLeft関数内に次のコードを追加します。
react-hooks-timer / src / App.js
// ...
const calculateTimeLeft = () => {
let year = new Date().getFullYear();
let difference = +new Date(`10/01/${year}`) - +new Date();
let timeLeft = {};
if (difference > 0) {
timeLeft = {
days: Math.floor(difference / (1000 * 60 * 60 * 24)),
hours: Math.floor((difference / (1000 * 60 * 60)) % 24),
minutes: Math.floor((difference / 1000 / 60) % 60),
seconds: Math.floor((difference / 1000) % 60)
};
}
}
// ...
このコードでは、日、時間、分、秒の数値を切り捨て、余りを削除して整数値を取得します。 次に、differenceを比較して、0より大きいかどうかを確認できます。
最後に、コンポーネントの他の場所で値を使用できるように、timeLeftを返す必要があります。
calculateTimeLeft関数内に次のコードを追加します。
react-hooks-timer / src / App.js
// ...
const calculateTimeLeft = () => {
let year = new Date().getFullYear();
let difference = +new Date(`10/01/${year}`) - +new Date();
let timeLeft = {};
if (difference > 0) {
timeLeft = {
days: Math.floor(difference / (1000 * 60 * 60 * 24)),
hours: Math.floor((difference / (1000 * 60 * 60)) % 24),
minutes: Math.floor((difference / 1000 / 60) % 60),
seconds: Math.floor((difference / 1000) % 60)
};
}
return timeLeft;
}
// ...
Hacktoberfestまでの残り時間を計算する関数を作成したので、タイマーを制御および更新するアプリの状態を追加できます。
ステップ4—useStateおよびuseEffectを使用してアプリの状態を更新する
React Hooksを使用すると、既存の機能コンポーネントをクラスに変換せずに、それらに状態管理機能を追加できます。
このステップでは、useStateおよびuseEffectフックをReactからインポートして、このコンポーネントの状態を管理します。
App.jsファイルの先頭で、インポートステートメントにuseStateとuseEffectを追加します。
react-hooks-timer / src / App.js
import React, { useEffect, useState } from "react";
// ...
このコードは、Reactから利用できるこれらの特定のフックとその機能を使用することをReactに通知します。
カウントダウンタイマーを機能させるには、状態を更新するために以前にコーディングした残り時間のメソッドを接続する必要があります。
calculateTimeLeft関数の後に次のコードを追加します。
react-hooks-timer / src / App.js
// ... const [timeLeft, setTimeLeft] = useState(calculateTimeLeft()); // ...
このJavaScript構文は、 arraydestructuringと呼ばれます。
useStateメソッドは、初期状態を設定するパラメーターを受け取り、現在の状態を含む配列と状態を設定する関数を返します。
timeLeftは、間隔の残り時間オブジェクトを運び、状態を設定するメソッドを提供します。 コンポーネントのロード時に、timeLeft値は現在の残り時間の値に設定されます。
次に、useEffectフックを使用して、コンポーネントの副作用に対処します。
注: 副作用は、実行されている関数の範囲外の何かに影響を与えるものです。
このソリューションでは、useEffectフック内でsetTimeoutメソッドを使用します。 setTimeoutおよび同様のsetIntervalメソッドは、useEffectフック内で使用される場合の一般的なReactパターンです。
ReactのsetTimeoutメソッドのようなほとんどの非同期動作は、useEffectフックとuseStateフックの組み合わせで定義されます。
注: React Docs のこのセクションで、setTimeoutやsetIntervalなどのメソッドをいつどのように使用するかについて詳しく読むことができます。
useState()関数の後に次のコードを追加します。
react-hooks-timer / src / App.js
// ...
const [timeLeft, setTimeLeft] = useState(calculateTimeLeft());
useEffect(() => {
const timer = setTimeout(() => {
setTimeLeft(calculateTimeLeft());
}, 1000);
});
// ...
useEffectは、残り時間を更新するものです。 デフォルトでは、Reactはレンダリングのたびにエフェクトを再呼び出しします。
変数timeLeftが状態で更新されるたびに、useEffectが起動します。 発火するたびに、タイマーを1秒(または1,000ms)に設定します。これにより、その時間が経過した後の残り時間が更新されます。
その後、サイクルは毎秒続きます。
スタックタイムアウトとエラーの原因となる可能性を排除するために、useEffectフック内にもclearTimeoutメソッドを追加します。
clearTimeoutメソッドを追加し、可変タイマーをパラメーターとして渡します。
react-hooks-timer / src / App.js
// ...
useEffect(() => {
const timer = setTimeout(() => {
setTimeLeft(calculateTimeLeft());
}, 1000);
return () => clearTimeout(timer);
});
// ...
return関数は、コンポーネントの最初の実行を除いて、useEffectがtimerを実行するたびに実行され、コンポーネントがマウント解除されている場合はタイムアウトをクリアします。
状態がcalculateTimeLeft()オブジェクトに設定され、エフェクトフック内で更新されているので、これを使用してディスプレイコンポーネントを構築できます。
ステップ5—Object.keysを使用する
このステップでは、Object.keysを使用して、timeLeftオブジェクトを反復処理し、表示コンポーネントを構築します。 表示コンポーネントを使用して、Hacktoberfestが始まるまでの残り時間を表示します。
まず、useEffectフックの下にtimerComponentsという名前の新しい変数を作成します。
react-hooks-timer / src / App.js
// ... const timerComponents = []; // ...
timeLeftのキーを繰り返し処理した後、この変数を使用して、残り時間で新しいJSXコンポーネントをプッシュします。
次に、 Object.keys を使用して、calculateTimeLeft関数から返されたtimeLeftオブジェクトを反復処理します。
このコードをtimerComponents変数に追加します。
react-hooks-timer / src / App.js
// ...
const timerComponents = [];
Object.keys(timeLeft).forEach((interval) => {
if (!timeLeft[interval]) {
return;
}
timerComponents.push(
<span>
{timeLeft[interval]} {interval}{" "}
</span>
);
});
// ...
ここで、コードはtimeLeftオブジェクトのプロパティをループします。 タイマー間隔の値がゼロより大きい場合、timerComponents配列に要素が追加されます。
注:コード内の余分な{" "}は、画面に表示されたときに残り時間を表示する間隔が互いにぶつからないようにするために使用されます。
{}を使用すると、JSX内でJavaScriptを使用でき、""でスペースを追加できます。
これで、Appコンポーネントのreturnステートメントに新しいJSXを追加して、Hacktoberfestまでの残り時間を表示する準備が整いました。
ステップ6—残り時間を表示する
このステップでは、JSXコンポーネントをアプリコンポーネントのreturnステートメントに追加します。 三項演算子を使用して、残り時間があるかどうか、またはHacktoberfestの時間かどうかを確認します。
timerComponents配列を使用するには、その長さを確認して返すか、タイマーがすでに経過していることをユーザーに通知する必要があります。
returnステートメント内に次のコードを追加します。
react-hooks-timer / src / App.js
// ...
return (
<div>
{timerComponents.length ? timerComponents : <span>Time's up!</span>}
</div>
);
// ...
React JSXコンポーネントでは、JavaScriptifステートメントの代わりに三項演算子を使用します。 これは、JSX内では式のみが許可されているためです。
コードのtimerComponents.length行は、timerComponents配列内に何かがあるかどうかを確認し、ある場合はそれをレンダリングします。ない場合は、Time's up!をレンダリングします。
次に、returnステートメントにさらに2つのJSXコンポーネントを追加して、カウントダウンしているものをユーザーに知らせます。
react-hooks-timer / src / App.js
// ...
return (
<div>
<h1>Hacktoberfest 2020 Countdown</h1>
<h2>With React Hooks!</h2>
{timerComponents.length ? timerComponents : <span>Time's up!</span>}
</div>
);
// ...
2020をハードコーディングする代わりに現在の年を使用するには、新しい状態変数を作成し、初期状態をnew Date().getFullYear();に設定します。
最初のuseState()変数の後に、次のコードを追加します。
react-hooks-timer / src / App.js
// ... const [timeLeft, setTimeLeft] = useState(calculateTimeLeft()); const [year] = useState(new Date().getFullYear()); // ...
このメソッドは、calculateTimeLeft関数で使用したように現在の年を取得します。
次に、ハードコードされた2020をh1から削除してyearに置き換えることができます。
react-hooks-timer / src / App.js
// ...
return (
<div>
<h1>Hacktoberfest {year} Countdown</h1>
<h2>With React Hooks!</h2>
{timerComponents.length ? timerComponents : <span>Time's up!</span>}
</div>
);
// ...
これにより、状態変数が表示され、常に現在の年になります。 完成したプロジェクトは次のようになります。
このGitHubリポジトリをチェックして、完全なコードを確認してください。
結論
このチュートリアルでは、useStateおよびuseEffectフックを使用してカウントダウンUIコンポーネントを構築し、アプリケーションの状態を管理および更新しました。
ここから、 Reactコンポーネントのスタイリングを使用して学習を続け、より魅力的なカウントダウンUIを作成できます。
また、DigitalOceanの How To Code in React.js シリーズ全体をフォローして、Reactを使用した開発の詳細を学ぶこともできます。