#投票アプリ作成中、よくわからない警告に遭遇
投票作成ページにて、投票を作成すると、投票を表示させるメインページに戻るが、その際に毎回、以下のような警告が出ていた。
######Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
######(日本語)警告:マウントされていないコンポーネントでReact状態の更新を実行することはできません。 これは何もしませんが、アプリケーションのメモリリークを示しています。 修正するには、useEffectクリーンアップ関数のすべてのサブスクリプションと非同期タスクをキャンセルします。
###警告が出る理由
useEffet内で、まだ、firebaseからすべて読み込まれていないのに、setQuestionsを実行しようとするから警告が出る。
const VotesList = () => {
const [questions, setQuestions] = useState(null);
useEffect(() => {
firebase
.firestore()
.collection("questions")
.orderBy("timestamp", "desc")
.onSnapshot((snapshot) => {
const questions = snapshot.docs.map((doc) => {
return {
username: doc.data().username,
question: doc.data().question,
answer1: doc.data().answer1,
answer1Id: doc.data().answer1Id,
answer2: doc.data().answer2,
answer2Id: doc.data().answer2Id,
docid: doc.id, //<- keyを設定するためにidを取得、あとで削除機能等をつける
};
});
setQuestions(questions);
});
}, []);
return (
<>
<ul>
{questions?.map((question) => {
return <CountVotes question={question} key={question.docid} />;
})}
</ul>
</>
);
};
###対処法
下記のように書き直すことで、警告は出なくなった。
アンマウント時にはsetQuestionsは実行せず、
マウント時のみsetQuestionsが実行するようにする。
まだDOMに無い時には return dispose で一度回避するイメージ。
useEffect(() => {
let disposed = false;
const dispose = () => {
disposed = true;
};
firebase
.firestore()
.collection("questions")
.orderBy("timestamp", "desc")
.onSnapshot((snapshot) => {
const questions = snapshot.docs.map((doc) => {
return {
username: doc.data().username,
question: doc.data().question,
answer1: doc.data().answer1,
answer1Id: doc.data().answer1Id,
answer2: doc.data().answer2,
answer2Id: doc.data().answer2Id,
docid: doc.id, //<- keyを設定するためにidを取得、あとで削除機能等をつける
};
});
!disposed && setQuestions(questions);
});
return dispose;
}, []);