繁体   English   中英

具有不同 props 的相同组件的条件渲染不会卸载 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 的 Sidebar 组件

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 我找到了解决方案!!!! 很简单,只需为您想要有条件地渲染的组件指定一个关键属性,但使用不同的道具,这告诉 react 这是一个新组件。 在我的示例中,它是 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  

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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