简体   繁体   中英

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

I'm working on a react web application the problem that I have is that I'm doing a conditional rendering of the same component with different props but that does not unmount it then remounts it again which means that the component did mount cycle is never run again and the component is never initialized again

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

this is the code and i want SidebarChat to unmounts than mounts when menu changes.

this is SidebarChat code

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;

and this is the Sidebar Component where I include SidebarChat in it

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 I found the solution !!!!!. It's simple just specify a key attribute to The component you want to render conditionally but with different props, this tells react that it's a new component. In my example it's the SidebarChat component

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  

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM