Firebase 数据更改状态但不呈现组件

Posted

技术标签:

【中文标题】Firebase 数据更改状态但不呈现组件【英文标题】:Firebase data changes state but does not render component 【发布时间】:2021-10-16 08:38:17 【问题描述】:

我正在尝试为 User 集合中的特定用户附加一个监听器到 chatRoomIds 子集合。在检索特定用户的 chatroomIds 后,我必须遍历每个以从 chatRoomIds 数组中获取特定的 chatRoom 文档,其中每个element 是一个包含 chatRoomId 的对象,将用于查询特定的聊天室。问题是状态正常工作但不会呈现消息卡组件,除非我在反应开发工具中的消息组件中切换另一个状态加载完所有内容后,消息会再次链接。

function Message() 

const [currentUser] = useAuthState(auth)

const [user] = useStateValue()
const show, setNotificationPopup, setShow = useChat();
const [chats, setChats] = useState([])
const [loading, setLoading] = useState(true)
const [chatRoomArraySnap, error] = useCollection(db.collection("Users").doc(user?.uid).collection('ChatRoomIds'))
const chatList = []

const setLoader, loader = useLoader();
let chatRoomIds = []
let params = useParams();
const messageId = params.id;
const userObj = 
    email: user?.email,
    objId: user?.uid,

    userName: user?.displayName
;


useEffect(() => 
    
        params.id ? setShow(true)
            :
            setShow(false)
    

, [])

useEffect(() =>
    // chatList = []
    if(user.uid)
        db.collection("Users").doc(user.uid).collection('ChatRoomIds').get()
            .then(
            snapshot => 

                snapshot.docs.map((each) => 

                    // chatRoomIds.push(each.data())
                    db.collection('ChatRooms').where("chatRoomId", "==", each.data().id).orderBy('dateLastUpdated','desc').onSnapshot(snapshot => 
                        snapshot.docs.forEach(doc => 
                            chats.push(doc.data())
                            console.log(doc.data())
                        )

                        // setChats(chatList)
                        setLoading(false)





                        // snapshot.docChanges().forEach((change) => 
                        //                            if (change.type === "added") 
                        //                                console.log("New : ", change.doc.data());
                        //                                chatList.push(change.doc.data())
                        //
                        //                            
                        //                            if (change.type === "modified") 
                        //                                console.log("Modified : ", change.doc.data());
                        //                                setNotificationPopup(change.doc.data())
                        //
                        //                            
                        //                            if (change.type === "removed") 
                        //                                console.log("Removed : ", change.doc.data());
                        //                            
                        //                        )


                    )

                )
                console.log(chatRoomIds)
                // chatRoomIds?.map((each) => 
                //     db.collection('ChatRooms').where("chatRoomId", "==", each.id).orderBy('dateLastUpdated','desc').onSnapshot(snapshot => 
                //         snapshot.docs.forEach(doc => 
                //             chatList.push(doc.data())
                //             console.log(doc.data())
                //         )
                //
                //         setChats(chatList)
                //         setLoading(false)
                //
                //
                //
                //
                //
                //         // snapshot.docChanges().forEach((change) => 
                //         //                            if (change.type === "added") 
                //         //                                console.log("New : ", change.doc.data());
                //         //                                chatList.push(change.doc.data())
                //         //
                //         //                            
                //         //                            if (change.type === "modified") 
                //         //                                console.log("Modified : ", change.doc.data());
                //         //                                setNotificationPopup(change.doc.data())
                //         //
                //         //                            
                //         //                            if (change.type === "removed") 
                //         //                                console.log("Removed : ", change.doc.data());
                //         //                            
                //         //                        )
                //
                //
                //     )
                // )
            

        )


        console.log(chatList)
        // if (chatRoomArraySnap) 
        //
        //     chatRoomArraySnap.docs.map((each) => 
        //         chatRoomIds.push(each.data())
        //     )
        //     // chatList=[]
        //     // setChats([])
        //
        //     chatRoomIds.map((each) => 
        //         db.collection('ChatRooms').where("chatRoomId", "==", each.id).orderBy('dateLastUpdated','desc').onSnapshot(snapshot => 
        //             snapshot.docs.forEach(doc => 
        //                 chatList.push(doc.data())
        //             )
        //
        //
        //
        //
        //
        //
        //             // snapshot.docChanges().forEach((change) => 
        //             //                            if (change.type === "added") 
        //             //                                console.log("New : ", change.doc.data());
        //             //                                chatList.push(change.doc.data())
        //             //
        //             //                            
        //             //                            if (change.type === "modified") 
        //             //                                console.log("Modified : ", change.doc.data());
        //             //                                setNotificationPopup(change.doc.data())
        //             //
        //             //                            
        //             //                            if (change.type === "removed") 
        //             //                                console.log("Removed : ", change.doc.data());
        //             //                            
        //             //                        )
        //
        //
        //         )
        //     )
        //     setChats(chatList)
        //     console.log(chatList)
        //
        // 
    

,[])

return (
    <>


        <Header/>
        <div className='container'>


            <div className='message '>
                <div className='row'>
                    <div className='col-md-4 col-lg-4 col-sm-12 lg-view'>
                        <div className=' pt-3 user-list-section'>
                            <div className='lg-view'>
                                <h5 className='text-light ml-5 mb-5`'>Messages</h5>
                                <div className=`d-flex align-items-center`>
                                    <Search  functionHandler=handleSearchChat props='#13161A'/>
                                    <CreateGroupBtn/>
                                </div>

                            </div>
                            <div className='user-list'>
                                !loading && chats ? chats.map(chat => 
                                    // console.log(chat.data());
                                    return (<>

                                            <MessageCard  key=chat.chatRoomId
                                                          id=chat.chatRoomId chats=chat/>


                                        </>
                                    )
                                ) : <></>

                            </div>


                        </div>


                    </div>
                    
                        !show ? <>
                                <div className='sm-view   w-100 pl-3 pr-3 '>
                                    <div className=' w-100  d-flex justify-content-center  pt-4'>
                                        <div className='flex-grow-1'>
                                            <h4 className='text-light'>Messages</h4>
                                            <p>Talk with your friends</p>


                                        </div>

                                        <div className="search-container flex-grow-1 ">
                                            <div className='search  d-flex float-right'>
                                                <CreateGroupBtn/>
                                            </div>


                                        </div>

                                    </div>
                                    <Search functionHandler=handleSearchChat/>


                                </div>

                                <div className='col-md-4 col-lg-4 col-sm-12 sm-view'>
                                    <div className=' pt-3 user-list-section'>
                                        <div className='lg-view'>
                                            <h5 className='text-light ml-5 mb-5`'>Messages</h5>
                                            <div className=`d-flex align-items-center`>
                                                <Search functionHandler=handleSearchChat props='#13161A'/>
                                                <CreateGroupBtn/>
                                            </div>


                                        </div>
                                        <div className='user-list'>
                                            !loading && chats !== undefined && chats !== null && chats ? chats.map(chat => 
                                                // console.log(chat.data());
                                                return (<>

                                                        <MessageCard  key=chat.chatRoomId
                                                                     id=chat.chatRoomId chats=chat/>


                                                    </>
                                                )
                                            ) : <></>
                                        </div>


                                    </div>


                                </div>

                            </>
                            :
                            <>
                                <div className='col-md-8 p-0 col-lg-8 col-sm-12'>
                                    
                                        messageId && currentUser.email && <MessageWindow/>

                                    

                                </div>

                            </>
                    
                </div>
            </div>
        </div>
        !show && <MobileNavbar/>
    </>

);

///工作代码

function Message() 

const [currentUser] = useAuthState(auth)

const [user] = useStateValue()
const show, setShow = useChat();
const [chats, setChats] = useState([])
const [loading, setLoading] = useState(true)

let params = useParams();
const messageId = params.id;



useEffect(() => 
    
        params.id ? setShow(true)
            :
            setShow(false)
    

, [])

useEffect(() => 
    if (user.uid) 
        db.collection("Users")
            .doc(user.uid)
            .collection("ChatRoomIds")
            .get()
            .then((snapshot) => 
                snapshot.docs.map((each) => 
                    db.collection("ChatRooms")
                        .where("chatRoomId", "==", each.data().id)
                        .orderBy("dateLastUpdated", "desc")
                        .onSnapshot((snapshot) => 
                            console.log(snapshot.docs.map((doc) => doc.data()))
                            setChats((chats) =>
                                chats.concat(snapshot.docs.map((doc) => doc.data()))
                            );
                            setLoading(false)
                        );
                );
            );
    
, []);

return (
    <>


        <Header/>
        <div className='container'>


            <div className='message '>
                <div className='row'>
                    <div className='col-md-4 col-lg-4 col-sm-12 lg-view'>
                        <div className=' pt-3 user-list-section'>
                            <div className='lg-view'>
                                <h5 className='text-light ml-5 mb-5`'>Messages</h5>
                                <div className=`d-flex align-items-center`>
                                    <Search functionHandler=handleSearchChat props='#13161A'/>
                                    <CreateGroupBtn/>
                                </div>

                            </div>
                            <div className='user-list'>
                                /*!loading && chats ? chats.map(chat => */
                                /*    // console.log(chat.data());*/
                                /*    return (<>*/

                                /*            <MessageCard key=chat.chatRoomId*/
                                /*                         id=chat.chatRoomId chats=chat/>*/


                                /*        </>*/
                                /*    )*/
                                /*) : <></>*/

                            </div>


                        </div>


                    </div>
                    
                        !show ? <>
                                <div className='sm-view   w-100 pl-3 pr-3 '>
                                    <div className=' w-100  d-flex justify-content-center  pt-4'>
                                        <div className='flex-grow-1'>
                                            <h4 className='text-light'>Messages</h4>
                                            <p>Talk with your friends</p>


                                        </div>

                                        <div className="search-container flex-grow-1 ">
                                            <div className='search  d-flex float-right'>
                                                <CreateGroupBtn/>
                                            </div>


                                        </div>

                                    </div>
                                    <Search functionHandler=handleSearchChat/>


                                </div>

                                <div className='col-md-4 col-lg-4 col-sm-12 sm-view'>
                                    <div className=' pt-3 user-list-section'>
                                        <div className='lg-view'>
                                            <h5 className='text-light ml-5 mb-5`'>Messages</h5>
                                            <div className=`d-flex align-items-center`>
                                                <Search functionHandler=handleSearchChat props='#13161A'/>
                                                <CreateGroupBtn/>
                                            </div>


                                        </div>
                                        <div className='user-list'>
                                            !loading && chats ? chats.map(chat => 

                                                return (<>

                                                        <MessageCard key=chat.chatRoomId
                                                                     id=chat.chatRoomId chats=chat/>


                                                    </>
                                                )
                                            ) : <></>
                                        </div>


                                    </div>


                                </div>

                            </>
                            :
                            <>
                                <div className='col-md-8 p-0 col-lg-8 col-sm-12'>
                                    
                                        messageId && currentUser.email && <MessageWindow/>

                                    

                                </div>

                            </>
                    
                </div>
            </div>
        </div>
        !show && <MobileNavbar/>
    </>

);


export default Message;

【问题讨论】:

【参考方案1】:

你有很多注释掉的代码,但是没有注释掉的有一个明显的问题,状态突变。您正在直接推入chats 状态数组。这就是为什么您必须切换/更新一些其他状态以触发组件重新呈现和公开突变的原因。

您应该正确地将这些chat 更新排入队列。在最后一个/最里面的快照上,您应该使用功能状态更新来更新之前的状态,因为您正在循环工作,并连接一组新的聊天文档。

Array.prototype.concat

concat() 方法用于合并两个或多个数组。这种方法 不会改变现有数组,而是返回一个新数组。

Array.prototype.map

map() 方法创建一个新数组,其中填充了 在调用数组中的每个元素上调用提供的函数。

.onSnapshot((snapshot) => 
  setChats((chats) =>
    chats.concat(snapshot.docs.map((doc) => doc.data()))
  );
);

例子:

useEffect(() => 
  if (user.uid) 
    db.collection("Users")
      .doc(user.uid)
      .collection("ChatRoomIds")
      .get()
      .then((snapshot) => 
        snapshot.docs.map((each) => 
          db.collection("ChatRooms")
            .where("chatRoomId", "==", each.data().id)
            .orderBy("dateLastUpdated", "desc")
            .onSnapshot((snapshot) => 
              setChats((chats) =>
                chats.concat(snapshot.docs.map((doc) => doc.data()))
              );
            );
        );
      );
  
, []);

更新 - 解决重复问题

仍然使用功能状态更新,但首先通过过滤器运行 chats 数组,以检查是否没有具有匹配 chatRoomId 属性的新聊天。如果匹配,则返回 false 以将其从数组中删除,否则保留它。过滤器函数返回一个新数组,您可以将其连接到新的聊天结果。

useEffect(() => 
  if (user.uid) 
    db.collection("Users")
      .doc(user.uid)
      .collection("ChatRoomIds")
      .get()
      .then((snapshot) => 
        snapshot.docs.map((each) => 
          db.collection("ChatRooms")
            .where("chatRoomId", "==", each.data().id)
            .orderBy("dateLastUpdated", "desc")
            .onSnapshot((snapshot) => 
              const newChats = snapshot.docs.map((doc) => doc.data());
              setChats((chats) => 
                const filtered = chats.filter(chat => 
                  !newChats.some(newChat => 
                    newChat.chatRoomId === chat.chatRoomId
                  )
                );
                newChats.concat(filtered);
              );
            );
        );
      );
  
, []);

【讨论】:

效果很好!!!!!谢谢。尽管进行更改时它会返回更改的文档并将其添加到状态中,但我该如何消除它。查看更新的照片 @johnoula 对不起,我不清楚你在问什么。您基本上是说更改/更新的文档被添加为重复文件,您是在问如何防止这种情况发生吗?这与我的答案中的代码有关,还是注释掉的代码中的内容? 与您的代码相关。查看更新后的照片。是的,是重复的,是的。在照片中,“组”已更新并导致重复,我认为您的代码应该如此 @johnoula 我明白了。 chats 数组元素中是否有字段/属性可以匹配/过滤/比较 doc.data() @johnoula 抱歉,我应该更明确一点,我的意思是任何 id 或 GUID 唯一标识一个条目,因此可以丢弃重复项。您基本上想替换以前的副本,或者如果是新的则追加。这是正确的理解吗?

以上是关于Firebase 数据更改状态但不呈现组件的主要内容,如果未能解决你的问题,请参考以下文章

在父组件的状态更改中重新呈现子组件

reactjs - 状态更改后组件不呈现[重复]

是否可以在 Vue 应用程序中呈现 Firebase 数据的实时变化?

Firebase 停止监听 onAuthStateChanged

Firebase Realtime 数据库数据可以读取但不出现在数据库中?

在 React Native 中将状态从子组件传递到父组件