具有不同道具的同一组件的条件渲染不会在 ReactJS 中卸载组件

conditional rendering of the same component with different props does not unmount the component in ReactJS

我正在开发一个 React Web 应用程序,我遇到的问题是我正在使用不同的道具对同一组件进行条件渲染,但不会卸载它然后再次重新安装它,这意味着该组件挂载周期永远不会再 运行 并且组件永远不会再次初始化

menu === 1 ?
   <SidebarChat dataList={chats} title="Chats" />
: menu === 2 ?
   <SidebarChat dataList={rooms} title="Rooms" />
: menu === 3 ?
   <SidebarChat dataList={users} title="Chats" />
: null

这是代码,我希望 SidebarChat 在菜单更改时卸载而不是装载。

这是 SidebarChat 代码

import React, { useEffect, useState } from 'react';
import { Avatar, IconButton } from '@material-ui/core';
import { Add } from '@material-ui/icons';
import './SidebarChat.css';
import db from './firebase';
import { Link } from 'react-router-dom';



function SidebarChat({ dataList, title }) {
    const [messages, setMessages] = useState([]);

    const createChat = () => {
        const roomName = prompt("Please enter name for chat");

        if (roomName) {
            //Do some clever database stuff right here .....
            db.collection("rooms").add({
                name: roomName,
            })
        }
   }

    useEffect(() => {
        console.log("first mount of " + title)
    }, [])

    useEffect(() => {
        if (dataList) {
            console.log(dataList);
            var unsubscribe = dataList.map((data, i) => {
                return 
db.collection("rooms").doc(data.id).collection("messages").orderBy("timestamp", 
"desc").onSnapshot(snap => {
                    if (snap.docs[0]) {
                        console.log(snap.docs[0].data())
                       setMessages(message => {
                            const arr = [...message];
                            arr[i] = snap.docs[0].data().message;
                            return arr;
                        })
                    }
                })
            });
            //console.log(messages);
        }
        return () => {
            if (unsubscribe) {
                unsubscribe.forEach(sub => sub())
            }
        }
    }, [dataList])

    console.log(title)
    console.log(messages)

    return (
        <div className="sidebar__chat--container">
            <div className="sidebar__chat--addRoom" onClick={createChat}>
                <IconButton >
                    <Add />
                </IconButton>
            </div>
            {dataList && messages.length > 0 ?
                <React.Fragment>
                    <h2>{title} </h2>
                    {dataList.map((data, i) => data ?
                        <Link key={data.id} to={{
                            pathname: `/room/${data.id}`,
                            state: {
                                photoURL: `${data.photoURL ? data.photoURL : 
`https://avatars.dicebear.com/api/human/${data.id}.svg`}`,
                               name: data.name,
                            }
                        }} >
                            <div className="sidebar__chat">
                                <Avatar src={`${data.photoURL ? data.photoURL : 
`https://avatars.dicebear.com/api/human/${data.id}.svg`}`} />
                                <div className="sidebar__chat--info">
                                    <h2>{data.name} </h2>
                                    <p>{messages[i]}</p>
                               </div>
                            </div>
                       </Link> :
                        null
                    )}
                </React.Fragment>
                : null
            }
        </div>
    )
}

export default SidebarChat;

这是我在其中包含 SidebarChat 的边栏组件

import React, { useEffect, useState } from 'react';
import SidebarChat from './SidebarChat';
import { Avatar, IconButton } from '@material-ui/core';
import { Message, PeopleAlt, Home, ExitToApp as LogOut, SearchOutlined, DonutLarge as DonutLargeIcon, 
Chat as ChatIcon } from '@material-ui/icons';
import db, { auth } from "./firebase";
import { useStateValue } from './StateProvider';
import { NavLink, Route, Switch, Link } from 'react-router-dom'
import './Sidebar.css';

const height = window.innerHeight;

if (window.innerWidth > 760) {
    var Nav = (props) =>
         <div className={`${props.classSelected ? "sidebar__menu--selected" : ""}`} onClick= 
{props.click}>
             {props.children}
         </div>
 } else {
      var Nav = NavLink;
 }

function Sidebar() {
     const [rooms, setRooms] = useState([]);
     const [users, setUsers] = useState([]);
     const [chats, setChats] = useState([]);
     const [menu, setMenu] = useState(1);
     const [{ user }] = useStateValue();

useEffect(() => {
    const unsubscribe1 = db.collection("rooms").onSnapshot(snapshot => {
        setRooms(
            snapshot.docs.map(doc => ({
                id: doc.id,
                ...doc.data(),
            }))
        )
    })

    const unsubscribe2 = db.collection("users").orderBy("timestamp", "desc").onSnapshot(snap => {
        const arr = [];
        snap.docs.forEach(doc => {
            if (doc.id !== user.uid) {
                arr.push({
                    ...doc.data(),
                    id: doc.id > user.uid ? doc.id + user.uid : user.uid + doc.id,
                })
            }
        });
        setUsers(arr);
    });

    const unsubscribe3 = db.collection("users").doc(user.uid).collection("chats").orderBy("timestamp", "desc").onSnapshot(snap => {
        console.log(snap.docs);
        Promise.all(snap.docs.map(doc => {
            return db.collection("rooms").doc(doc.id).get();
        })).then(rooms => {
            console.log(rooms);
            const chat = rooms.map((room, i) => ({
                id: room.id,
                photoURL: snap.docs[i].data().photoURL,
                name: snap.docs[i].data().name,
                ...room.data(),
            }));
            console.log(chat);
            setChats(chat);
        })
    })

    return () => {
        unsubscribe1();
        unsubscribe2();
        unsubscribe3();
    }
}, []);

return (
    <div className="sidebar" style={{
        minHeight: window.innerWidth <= 760 ? height : "auto"
    }}>
        <div className="sidebar__header">
            <Avatar src={user?.photoURL} />
            <div className="sidebar__header--right">
                <IconButton>
                    <DonutLargeIcon />
                </IconButton>
                <IconButton>
                    <ChatIcon />
                </IconButton>
                <IconButton onClick={() => auth.signOut()} >
                    <LogOut />
                </IconButton>

            </div>
        </div>

        <div className="sidebar__search">
            <div className="sidebar__search--container">
                <SearchOutlined />
                <input placeholder="Search or start new chat" type="text" />
            </div>
        </div>

        <div className="sidebar__menu">
            <Nav
                classSelected={menu === 1 ? true : false}
                to="/"
                click={() => setMenu(1)}
                exact
                activeClassName="sidebar__menu--selected"
            >
                <div className="sidebar__menu--home">
                    <Home />
                    <div className="sidebar__menu--line"></div>
                </div>
            </Nav>
            <Nav
                classSelected={menu === 2 ? true : false}
                to="/rooms"
                click={() => setMenu(2)}
                activeClassName="sidebar__menu--selected"
            >
                <div className="sidebar__menu--rooms">
                    <Message />
                    <div className="sidebar__menu--line"></div>
                </div>
            </Nav>
            <Nav
                classSelected={menu === 3 ? true : false}
                to="/users"
                click={() => setMenu(3)}
                activeClassName="sidebar__menu--selected"
            >
                <div className="sidebar__menu--users">
                    <PeopleAlt />
                    <div className="sidebar__menu--line"></div>
                </div>
            </Nav>
        </div>

        {window.innerWidth <= 760 ?
            <>
                <Route path="/users" exact >
                    <SidebarChat dataList={users} title="Users" />
                </Route>
                <Route path="/" exact >
                    <>
                        {/*
                            <h2>Chats</h2>
                            <SidebarChat addNewChat />
                            {chats.map(room => room ? <SidebarChat key={room.id} id={room.id} name={room.name} photo={room.photoURL} /> : null)} */}
                        <SidebarChat dataList={chats} title="Chats" />
                    </>
                </Route>
                <Route path="/rooms" exact >
                    <>
                        <SidebarChat dataList={rooms} title="Rooms" />
                    </>
                </Route>
            </>
            :
                menu === 1 ?
                    <SidebarChat dataList={chats} title="Chats" />
                : menu === 2 ?
                    <SidebarChat dataList={rooms} title="Rooms" />
                : menu === 3 ?
                    <SidebarChat dataList={users} title="Chats" />
                : null  
            }
    </div>
);
};

export default Sidebar;

Guuuuuuuuuys 我找到了解决方案 !!!!!。 很简单,只需为要有条件地渲染但使用不同道具的组件指定一个键属性,这告诉反应它是一个新组件。 在我的示例中,它是 SidebarChat 组件

menu === 1 ?
    <SidebarChat key="chats" dataList={chats} title="Chats" />
: menu === 2 ?
    <SidebarChat key="rooms" dataList={rooms} title="Rooms" />
: menu === 3 ?
    <SidebarChat key="users" dataList={users} title="Users" />
: null