Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
401 views
in Technique[技术] by (71.8m points)

javascript - Infinite loop when working with react and react-firebase-hooks

I am working with a navigation bar that should be able to switch between multiple chat rooms using react and react-firebase-hooks. (https://github.com/CSFrequency/react-firebase-hooks)

However, the chat room will infinitely re-render itself when I choose a room in nav-bar.

I initially thought this is a router issue, but having each rooms sharing the same url, the issue persists.

Right now, when I choose a room using the nav bar, it will send that room number back to App.js using a callback function. App.js will pass that room number to ChatRoom.js, which will get the data from firestore, and re-render itself.

I struggled for several days trying to find anything that could cause the infinite loop with minimal success. Any help would be appreciated!

ChatRoom.js

import React, { useMemo, useRef, useState } from 'react';
import { withRouter } from 'react-router';
import { useCollectionData, useDocument, useDocumentData } from 'react-firebase-hooks/firestore';
import firebase, { firestore, auth } from '../Firebase.js';
import ChatMessage from './ChatMessage';


const ChatRoom2 = (props) => {

    console.log("chat room rendered");
    
    function saveQuery(){
        const channelid= props.channelid;
        const messagesRef = firestore.collection('messages').doc(channelid).collection('chats');
        const query = messagesRef.orderBy('createdAt').limitToLast(25);
        return [messagesRef,query];
    }

    var returnedVal = useMemo(()=>saveQuery , [props.channelid]);
    const messagesRef = returnedVal[0];
    const query = returnedVal[1];

    const [messages] = useCollectionData(query, { idField: 'id' });
    const [formValue, setFormValue] = useState('');
    
    const sendMessage = async (e) => {
        e.preventDefault();

        console.log(messagesRef);
        console.log(query);
        console.log(messages);

        const { uid, photoURL } = auth.currentUser;
        
        await messagesRef.add({
            text: formValue,
            createdAt: firebase.firestore.FieldValue.serverTimestamp(),
            uid,
            photoURL
        })

        setFormValue('');
    }
    return (<>
        <main>
            {messages && messages.map(msg => <ChatMessage key={msg.id} message={msg} />)}
        </main>

        <form onSubmit={sendMessage}>

            <input value={formValue} onChange={(e) => setFormValue(e.target.value)} placeholder="say something nice" />

            <button type="submit" disabled={!formValue}>???</button>

        </form>
    </>)
}


export default ChatRoom2;
question from:https://stackoverflow.com/questions/65867856/infinite-loop-when-working-with-react-and-react-firebase-hooks

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Issue Summary

useCollectionData memoizes on the query parameter but since a new query reference was declared each render cycle the firebase hook was rerun and updated collection and rerendered the component.

const { channelid } = props;
const messagesRef = firestore
  .collection('messages')
  .doc(channelid)
  .collection('chats');
const query = messagesRef // <-- new query reference
  .orderBy('createdAt')
  .limitToLast(25);

const [messages] = useCollectionData(
  query, // <-- reference update trigger hook
  { idField: 'id' },
);

Solution

query has only a dependency on the channelid prop value, so we can memoize the query value and pass a stable value reference to the useCollectionData hook.

const { channelid } = props;

const query = useMemo(() => {
  const messagesRef = firestore
    .collection('messages')
    .doc(channelid)
    .collection('chats');
  const query = messagesRef.orderBy('createdAt').limitToLast(25);
  return query;
}, [channelid]);

const [messages] = useCollectionData(
  query,  // <-- stable reference
  { idField: 'id' },
);

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...