由 UseEffect 中的父级异步函数定义的 props 传递给子组件在其 UseEffect 清理期间不会保留



请考虑以下代码:

父:

const Messages = (props) => {
const [targetUserId, setTargetUserId] = useState(null);
const [currentChat, setCurrentChat] = useState(null);
useEffect(() => {
const { userId } = props;
const initiateChat = async (targetUser) => {
const chatroom = `${
userId < targetUser
? `${userId}_${targetUser}`
: `${targetUser}_${userId}`
}`;
const chatsRef = doc(database, 'chats', chatroom);
const docSnap = await getDoc(chatsRef);
if (docSnap.exists()) {
setCurrentChat(chatroom);
} else {
await setDoc(chatsRef, { empty: true });
}
};
if (props.location.targetUser) {
initiateChat(props.location.targetUser.userId);
setTargetUserId(props.location.targetUser.userId);
}
}, [props]);
return (
...
<Chat currentChat={currentChat} />
...
);
};

孩子:

const Chat = (props) => {
const {currentChat} = props;
useEffect(() => {
const unsubscribeFromChat = () => {
try {
onSnapshot(
collection(database, 'chats', currentChat, 'messages'),
(snapshot) => {
// ... //
}
);
} catch (error) {
console.log(error);
}
};
return () => {
unsubscribeFromChat();
};
}, []);
...

我正在处理的问题是,孩子的UseEffect清理功能,这取决于从它的父传递的chatroomprop,抛出TypeError错误,因为显然chatroom是空的。也就是说,当父组件卸载时,它会变为null,当组件被加载时,它会正常工作,并且props被正确识别。

我尝试了不同的方法来解决这个问题。我唯一能做到这一点的方法是,当我把子组件的useEffect移动到父组件,并使用useRef()定义currentChat,老实说,这是不理想的。

为什么会发生这种情况?是否应该使用effect清理功能依赖于以前的状态?有什么合适的方法来解决这个问题吗?

currentChat是该效果的依赖性。如果为空,则unsubscribe应该提前返回。

const {currentChat} = props;
useEffect(() => {
const unsubscribeFromChat = () => {
if(!currentChat) return;
try {
onSnapshot(
collection(database, 'chats', currentChat, 'messages'),
(snapshot) => {
// ... //
}
);
} catch (error) {
console.log(error);
}
};
return () => {
unsubscribeFromChat();
};
}, [currentChat]);

但这听起来不像是最好的解决方案。我认为你应该在同一个组件中处理所有的订阅/取消订阅。你不应该在父目录中订阅,然后在子目录中退订。

编辑:

啊,这里发生了一堆不好的事情。你的userId来自props - props。location。targetuser。userId然后你把它设置为状态。不这是州政府,这只是个道具。状态是组件拥有的东西,是组件创建的数据,是组件发出的数据,是组件的事实来源(你懂的)。如果你的组件没有创建它(像userId是通过location.targetUser对象进入道具),那么它不是状态。试图让道具与状态保持同步并担心所有的边缘情况是徒劳的。这不是状态。

同样,将[props]作为效果的依赖项也是一种代码调用。你应该把那些需要检测变化的道具分开,把它们单独放到依赖数组中。

最新更新