为啥我在 React JS 中的代码会进入满足这两个条件的无限循环?

Posted

技术标签:

【中文标题】为啥我在 React JS 中的代码会进入满足这两个条件的无限循环?【英文标题】:Why does my code in React JS goes to endless loop satisfying both conditions?为什么我在 React JS 中的代码会进入满足这两个条件的无限循环? 【发布时间】:2020-03-19 17:28:34 【问题描述】:

import React,  useEffect, useState  from "react";
import  connect  from "react-redux";
import  Redirect  from "react-router-dom";
import firebase from '../../config/firebaseConfig'

import SingleEventSummary from './SingleEventSummary'

import  getEvent  from "./../../store/actions/eventActions";

import "./SingleEvent.css";
const SingleEvent = props => 
	const id = props.match.params.id;

	const [eventItem, seteventItem] = useState([]);
	const [isFavourite, setIsFavourite] = useState("no");

	//getting specific event
	useEffect(() => 

		const db = firebase.firestore().collection('newEvents').doc(id)

		db.onSnapshot(snapshot => 
			seteventItem(snapshot.data())
		)
	, [id])

	//checking if there is favourite
	useEffect(() => 
		const db = firebase.firestore().collection('users').doc(props.auth.uid)
	  
		db.get().then(snapshot => 
		  const data = snapshot.data()
		  const faves = data && snapshot.data().favorites || []
	  
		  faves.includes(id) ? setIsFavourite("yes") : setIsFavourite("no")
		,(error) => console.error(error))
	  ,[isFavourite])
    

	//setting as favourites
	const favouriteClick = (uid, eid) => 
		debugger;
		let initFav = firebase.firestore().collection('users').doc(uid);
		initFav.get().then(snapshot => 
			const arrayUnion = firebase.firestore.FieldValue.arrayUnion(eid);
			initFav.update(
				favorites: arrayUnion,
			);
			setIsFavourite("yes")
		,(error) => console.error(error))
	

	//remove favourites
	const removeFavourite = () => 
		debugger;
		const initFavo = firebase.firestore().collection('users').doc(props.auth.uid);
		initFavo.get().then(snapshot => 
			if (snapshot.data().favorites) 
				if (snapshot.data().favorites.includes(id)) 
					let data = snapshot.data().favorites.filter(el => el != id )
					initFavo.update(
						favorites: data,
					);
					setIsFavourite("no")
				
			
		,(error) => console.error(error))
		return () => initFavo()
	

	console.log("wtf is this shit", isFavourite)
  
	if (isFavourite == "no") 
		return (
			<main className="single-event_main">
				<a className="waves-effect waves-light btn" onClick=favouriteClick(props.auth.uid, id)>Add As Favourites!!</a>
			</main>
		);

	 else 
		return (
			<main className="single-event_main">
				<div className="row">
					<div className="col s6">
						<a className="waves-effect waves-light btn" disabled>Favourite Event!!</a>
					</div>
					<div className="col s6">
						<a className="waves-effect waves-light btn" onClick=removeFavourite>Remove From Favourites!!</a>
					</div>
				</div>
			</main>
		);
	 
;

export default SingleEvent;

我正在尝试设置挂钩中的值,比较用户数据库中是否存在事件 ID(如果他/她已将该事件设置为收藏夹)。

....
const [isFavourite, setIsFavourite] = useState("no");

//checking if there is favourite
useEffect(() => 
    debugger;
    const db = firebase.firestore().collection('users').doc(props.auth.uid)
    db.onSnapshot(snapshot => 
        debugger;
        if(snapshot.data()) 
            if (snapshot.data().favorites) 
                if (snapshot.data().favorites.includes(id)) 
                    setIsFavourite("yes")
                
                else if(!snapshot.data().favorites.includes(id))
                    setIsFavourite("no")
                
            
        
    , (error) => console.error(error));
    return () => db()
,[])
....

问题是,react 在这两种情况下都会无休止地设置钩子值是和否。一直卡在这几个小时。

任何形式的帮助将不胜感激!!!

【问题讨论】:

id 在哪里定义或传递?我看到它在includes(id) 中使用,但不在代码中 您不需要 else If 语句。您可以用简单的 else 替换它。因为你的 else If 与你的 if 语句完全相反 这里看起来也没什么问题。需要查看更多代码。可能是别的东西。 我怀疑你在 setIsFavourite() 做某事。您能否在问题中添加代码。 @HolyMoly 是从 param 传递的 id const id = props.match.params.id; 【参考方案1】:

只是提供了一点重构->这只是更容易阅读

useEffect(() => 
  const db = firebase.firestore().collection('users').doc(props.auth.uid)

  db.onSnapshot(snapshot => 
    const data = snapshot.data()
    const faves = data && snapshot.data().favorites || []

    faves.includes(id) ? setIsFavourite("yes") : setIsFavourite("no")
  ,(error) => console.error(error))

  return () => db()
,[])

我不明白为什么你的代码会循环,也许我们需要更多代码,就像上面评论者提到的那样。

【讨论】:

嗨,我添加了完整的相关代码。感谢重构代码。【参考方案2】:

如果您正在更新 setIsFavourite() 中的 firebase,那么您正在创建一个将由 .onSnapshot 侦听器接收的更改。这将导致无限循环:条件触发器更改 > 侦听条件 > 条件触发器更改 > 无限循环。

您需要从.onSnapshot 切换到一次性.get 侦听器,或者您需要添加一个条件以防止在这种情况下传播更改。此自定义条件将特定于您的实现,除非您显示使用更多代码并帮助我们了解您要实现的目标(但这应该是一个单独的问题),否则我们实际上无法提供帮助。所以我怀疑在这种情况下是前者。

【讨论】:

嗨,我已经更新了完整的相关代码。 setIsFavourite 只是一个基于从 firebase 接收到的值设置的钩子。 您的更新没有解决我的问题。你正在创造一个无限循环的变化,因为没有什么可以阻止它。您有一个监听器进行更改,更改触发监听器,触发更改,触发监听器,触发更改...只需停止使用实时监听器并切换到一次性 getter。 我根据您的建议更新了代码,但仍然无法正常工作。烦人的事情是在每次渲染时,我的代码都会自动运行两个 onClick 事件。 那是因为你已经这样设置了。如果你不希望它们自动运行,那么onClick=favouriteClick(props.auth.uid, id)应该是onClick=() =&gt; favouriteClick(props.auth.uid, id)【参考方案3】:

你应该为这个钩子设置一个停止条件,useEffect 钩子会在你每次渲染时触发,所以你最终会改变 props 和渲染,然后触发 useEffect 改变 props 并触发 render 生命周期钩子。

你应该有类似的东西

useEffect(() => 
  // call database
,[setFavorite]) // here goes stop condition for useEffect

如果setFavorite 仍然是false,它将不会再次触发触发器,或者如果setFavorite 为假并且来自db 的请求将其设置为true,那么下次如果它再次触发useEffect 并且setFavorite 仍然是 true 然后 useEffect 不会执行。

更多详情请阅读官方文档https://reactjs.org/docs/hooks-effect.html

【讨论】:

【参考方案4】:

好的,现在您已经向我们展示了更多代码。我可以很有信心地说,这是因为您在“添加为收藏夹”按钮的 onClick 中调用了 favouriteClick。

这导致了一个奇怪的循环。 改变

onClick=favouriteClick(props.auth.uid, id)

onClick=() => favouriteClick(props.auth.uid, id)

不客气!

【讨论】:

WTH 人!!!赞!!!这有效!谢啦!!这对我来说太烦人了。您能否向我解释一下区别以及为什么现在可以使用? @Daniel Duong @AbhishekPokhrel 您在组件的每个渲染上都调用了 favouriteClick。通过创建箭头函数, favouriteClick 在实际单击之前不会被调用。在包装函数运行之前,函数块中的函数调用不会被执行。

以上是关于为啥我在 React JS 中的代码会进入满足这两个条件的无限循环?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我在 React JS 中遇到意外错误 [重复]

为啥我的 React 应用程序会出现这个错误?

为啥 React 应用程序在运行“npm start”命令时会出错?

React.js 和 webpack - 为啥它不允许 var、let、const?

为啥我在 chrome 开发工具性能面板中得到 30 fps,但 JS 和 React 都说是 60?

为啥 create-react-app 会同时创建 App.js 和 index.js?