質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.46%
TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

Q&A

0回答

1318閲覧

ReactJsのuseEffect内で毎分API Callさせたいが、1分に1回以上Callしてしまっているのを解消したい

hatsu

総合スコア1809

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

0グッド

1クリップ

投稿2021/05/02 07:20

編集2021/05/02 09:57

現状

React.js(17.0.2)、TypeScript(4.2.4)で時計(Clock)Componentと電車情報を1分に1回00秒のときにAPIで取得するTrainTimeTableComponentをHooksで作っております。

以下、コードの主要部分のみ抜粋したものです。

tsx

1function TrainTimeTable() { 2 const [stationName, setStationName] = useState<string>(); 3 // 別のClockコンポーネントで毎秒timeを現在時刻に変更しています 4 const { time } = useSelector((state: any) => state.timer); 5 const now = DayJs(time); 6 7 useEffect(() => { 8 if (shouldRefetch()) { apiCall(); } 9 }, [now]); 10 11 const shouldRefetch = () => { 12 return !stationName || now.format("ss") === "00" 13 } 14 15 const apiCall = async () => { 16 // stationNameないとき(=最初のマウント時)と、秒が00のときに発火しています 17 console.log("FETCH Train TimeTable", now); 18 const response: any = await axios.get(EKISPART_API_BASE_URL, 19 { 20 params: { 21 key: process.env.EKISPART_API_KEY, 22 date: now.format("YYYYMMDD"), 23 } 24 }) 25 const data = response.data.ResultSet.TimeTable; 26 setStationName(data.Station.Name); 27 } 28 29 return ( 30 <h1 className="text-xl">{stationName}駅の運行情報</h1> 31 ); 32} 33 34export default TrainTimeTable;

timeの更新を行っているコード

tsx

1function Clock() { 2 const { time } = useSelector((state: any) => state.timer); 3 const dispatch = useDispatch(); 4 5 useEffect(() => { 6 const timerId = setInterval(() => dispatch(tick(DayJs().format('YYYY/MM/DD HH:mm:ss'))), 1000); 7 8 return () => clearInterval(timerId); 9 }); 10 const now = DayJs(time); 11 12 return ( 13 <p className="text-2xl text-thinGray">{now.format('YYYY/MM/DD')}</p> 14 ); 15};

redux-toolkitを使っているのですが、timeの更新が1秒に1度のみ動いていることは以consoleで確認できましたと思われます。以下がdispatchで動かした関数にしこんだログです。

action! 2021/05/02 18:53:10 TimerSlice.tsx:18 action! 2021/05/02 18:53:11 TimerSlice.tsx:18 action! 2021/05/02 18:53:12 TimerSlice.tsx:18 ...

課題

apiCall関数が、stationNameないとき(=最初のマウント時)と、秒が00のときに発火しています。
が、consoleをみると00秒のときに、複数回 console.log("FETCH Train TimeTable", now); が走ってしまっています。
期待しているのは、00秒のときに1度だけ発火することです。

聞きたいこと

上記の課題である、なぜ複数回apiCallが走ってしまっているのかについて、原因と解消方法を知りたいです。
ご存じの方がいらっしゃればご教示いただけると幸いです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hoshi-takanori

2021/05/02 09:44

time が 1 秒よりも短い間隔で更新されてるのでは。
hoshi-takanori

2021/05/02 11:21

API の結果が 1 秒以内に返ってきて、setStationName で駅名が変わってればまた発火すると思いますが、駅名が同じなら発火しないはずですよね…。 あと、Clock の useEffect の第 2 引数に [] を指定した方がいいような。(API の発火とは関係ありませんが。)
hatsu

2021/05/02 12:17

> Clock の useEffect の第 2 引数に [] を指定した方がいいような。(API の発火とは関係ありませんが。) たしかにですね。修正しました。 >setStationName で駅名が変わってればまた発火すると思いますが、駅名が同じなら発火しないはずですよね…。 ですよね。。shouldRefetch()関数は基本1秒に1回実行されていますが、apiCall()が実行されたときだけ複数回実行されているようです。これがなにかヒントになりますかね、、、
hoshi-takanori

2021/05/02 12:50

TrainTimeTable に他にも state があったりしませんか? あと、const now = DayJs(time); ですが、time が同じでも now は別のオブジェクトになると思うので、useEffect の第 2 引数は [time] にして、now は useEffect のクロージャの中で作った方がいいかも。
hatsu

2021/05/02 13:09

> TrainTimeTable に他にも state があったりしませんか? はい、他にもstateが存在します。 > const now = DayJs(time); ですが、time が同じでも now は別のオブジェクトになると思うので、useEffect の第 2 引数は [time] にして、now は useEffect のクロージャの中で作った方がいいかも。 第2引数timeにしたら正常に1度のみ動くようになりました。ありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.46%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問