问题描述
我在一个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;
这是补充工具栏组件,我在其中添加了补充工具栏
import React,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我找到了解决方案!!!! 这很简单,只需为想要有条件渲染的组件指定一个key属性,但要使用不同的道具,这告诉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