如何克服 React hook useState 异步行为?
How to overcome the React hook useState async behavior?
我在 useState 异步行为方面遇到了一些问题,这也可能与我是新手的 Redux 相关。
import React, { useState, useEffect } from "react"
import { useSelector, useDispatch } from "react-redux"
import { Link } from "react-router-dom"
import {
getAlltopics,
joinAtopic,
leaveAtopic,
} from "../../../redux/actions/topicActions"
import Icon from "../Icon"
const TopicCard = ({ topics }) => {
const user = useSelector((state) => state.user)
const [join, setJoin] = useState(false)
const dispatch = useDispatch()
console.log(join)
const leaveTopicHandler = async () => {
setJoin(false)
dispatch(leaveAtopic(topics._id))
}
const JoinTopicHandler = () => {
setJoin(true)
dispatch(joinAtopic(topics._id))
}
useEffect(() => {
const checkJoinedUser = () => {
topics.members.map((member) => {
if (member._id === user?._id) setJoin(true)
})
}
checkJoinedUser()
dispatch(getAlltopics())
}, [join, dispatch])
return (
<div
key={topics._id}
className="flex flex-col justify-between w-48 h-72 bg-white shadow-xl rounded-br-3xl rounded-bl-3xl rounded-tr-3xl"
>
<Link to={`/topics/${topics._id}`}>
<section className="">
<img
src={topics.bannerImage}
alt="topic_Image"
className="object-cover h-48 w-full rounded-tr-3xl"
/>
</section>
<section className="border-b-2 border-grey-light ml-3 mr-3 h-12 flex items-center">
<h1 className="text-lg">{topics.title}</h1>
</section>
</Link>
<section>
<div className="flex justify-between">
<div className="flex p-3">
<Icon iconName="member" iconStyle="fill-inactive text-grey-dark" />
<span>{topics.members?.length}</span>
<Icon iconName="file" iconStyle="fill-inactive text-grey-dark" />
<span>{topics.recources?.length}</span>
</div>
<div className="p-3">
{join ? (
<button type="button" onClick={leaveTopicHandler}>
<Icon
iconName="follow"
iconStyle="fill-active text-grey-dark"
/>
</button>
) : (
<button type="button" onClick={JoinTopicHandler}>
<Icon
iconName="follow"
iconStyle="fill-inactive text-grey-dark"
/>
</button>
)}
</div>
</div>
</section>
</div>
)
}
我已经定义了一个 join
变量来处理一个按钮,根据它是 true 还是 false 将显示或不显示某些方面,此外,如果它是 false 用户可以加入主题,如果它为真,用户可以离开主题,因为它在函数 JoinTopicHandler
和 leaveTopicHandler
中很明显。在加入主题之前,它看起来像这样:before joining a topic, as it is possible to see, the join
variable it's set to false, because I am not in the topic. When joining the topic, after joining the topic, the join
variable is set to true, the button changed, although the user count didn't changed for 2 (sometimes it does, sometimes I have to refresh the page for it to render), but the weirdest thing is when leaving the topic, as it's shown in the console,leaving the topic join
变量变为 false 但随后它自己再次变为 true 并且按钮看起来仍然相同,我无法修复这个......
不知道 leaveAtopic 函数到底做了什么,我的猜测是因为 join
在你的 useEffect
挂钩依赖项中,点击离开按钮会发生什么:
leaveTopicHandler
是 运行
setJoin(false)
导致重新渲染,因为 join
是 useEffect 的依赖项,我们再次 运行 它
- 调度
leaveAtopic
开始,但我假设那里有异步逻辑
topics
还没有改变,所以当 useEffect
运行s topics.members
仍然包含用户
对于 join
,您可能甚至不需要 useState/useEffect,而是可以执行以下操作:
const join = !!topics.members.find((member) => member._id === user?._id))
所以我从我的应用程序后端开始有一些错误,首先,我没有返回更新的主题,因为我没有正确设置调用。
const addUserToTopicDb = async (topicId, user) => {
try {
return await Topic.findByIdAndUpdate(topicId, {
$push: { members: user },
}, {new: true});
} catch (error) {
throw new Error(error);
}
};
我必须添加 {new: true}
才能获得更新的主题。这是一个重大错误。其次,我在 reducer 上的代码无法正常工作,因为我是新手,并且通过解决此类问题来学习。
我将 reducer 代码更改为:
case JOIN_TOPIC:
return {
allTopics: state.allTopics.map((eachTopic) =>
eachTopic._id === action.payload.topic._id
? action.payload.topic
: eachTopic
),
}
case LEAVE_TOPIC:
return {
allTopics: state.allTopics.map((eachTopic) =>
eachTopic._id === action.payload.topic._id
? action.payload.topic
: eachTopic
),
}
这基本上意味着,如果我有一个具有相同 _id 的主题,请将其替换为我一开始没有返回的新更新主题。
在此之后,一切开始顺利进行。很遗憾我认为问题是由于 useState
... 当它一直在我的数据库设置和 reducer 中...
我在 useState 异步行为方面遇到了一些问题,这也可能与我是新手的 Redux 相关。
import React, { useState, useEffect } from "react"
import { useSelector, useDispatch } from "react-redux"
import { Link } from "react-router-dom"
import {
getAlltopics,
joinAtopic,
leaveAtopic,
} from "../../../redux/actions/topicActions"
import Icon from "../Icon"
const TopicCard = ({ topics }) => {
const user = useSelector((state) => state.user)
const [join, setJoin] = useState(false)
const dispatch = useDispatch()
console.log(join)
const leaveTopicHandler = async () => {
setJoin(false)
dispatch(leaveAtopic(topics._id))
}
const JoinTopicHandler = () => {
setJoin(true)
dispatch(joinAtopic(topics._id))
}
useEffect(() => {
const checkJoinedUser = () => {
topics.members.map((member) => {
if (member._id === user?._id) setJoin(true)
})
}
checkJoinedUser()
dispatch(getAlltopics())
}, [join, dispatch])
return (
<div
key={topics._id}
className="flex flex-col justify-between w-48 h-72 bg-white shadow-xl rounded-br-3xl rounded-bl-3xl rounded-tr-3xl"
>
<Link to={`/topics/${topics._id}`}>
<section className="">
<img
src={topics.bannerImage}
alt="topic_Image"
className="object-cover h-48 w-full rounded-tr-3xl"
/>
</section>
<section className="border-b-2 border-grey-light ml-3 mr-3 h-12 flex items-center">
<h1 className="text-lg">{topics.title}</h1>
</section>
</Link>
<section>
<div className="flex justify-between">
<div className="flex p-3">
<Icon iconName="member" iconStyle="fill-inactive text-grey-dark" />
<span>{topics.members?.length}</span>
<Icon iconName="file" iconStyle="fill-inactive text-grey-dark" />
<span>{topics.recources?.length}</span>
</div>
<div className="p-3">
{join ? (
<button type="button" onClick={leaveTopicHandler}>
<Icon
iconName="follow"
iconStyle="fill-active text-grey-dark"
/>
</button>
) : (
<button type="button" onClick={JoinTopicHandler}>
<Icon
iconName="follow"
iconStyle="fill-inactive text-grey-dark"
/>
</button>
)}
</div>
</div>
</section>
</div>
)
}
我已经定义了一个 join
变量来处理一个按钮,根据它是 true 还是 false 将显示或不显示某些方面,此外,如果它是 false 用户可以加入主题,如果它为真,用户可以离开主题,因为它在函数 JoinTopicHandler
和 leaveTopicHandler
中很明显。在加入主题之前,它看起来像这样:before joining a topic, as it is possible to see, the join
variable it's set to false, because I am not in the topic. When joining the topic, after joining the topic, the join
variable is set to true, the button changed, although the user count didn't changed for 2 (sometimes it does, sometimes I have to refresh the page for it to render), but the weirdest thing is when leaving the topic, as it's shown in the console,leaving the topic join
变量变为 false 但随后它自己再次变为 true 并且按钮看起来仍然相同,我无法修复这个......
不知道 leaveAtopic 函数到底做了什么,我的猜测是因为 join
在你的 useEffect
挂钩依赖项中,点击离开按钮会发生什么:
leaveTopicHandler
是 运行setJoin(false)
导致重新渲染,因为join
是 useEffect 的依赖项,我们再次 运行 它- 调度
leaveAtopic
开始,但我假设那里有异步逻辑 topics
还没有改变,所以当useEffect
运行stopics.members
仍然包含用户
对于 join
,您可能甚至不需要 useState/useEffect,而是可以执行以下操作:
const join = !!topics.members.find((member) => member._id === user?._id))
所以我从我的应用程序后端开始有一些错误,首先,我没有返回更新的主题,因为我没有正确设置调用。
const addUserToTopicDb = async (topicId, user) => {
try {
return await Topic.findByIdAndUpdate(topicId, {
$push: { members: user },
}, {new: true});
} catch (error) {
throw new Error(error);
}
};
我必须添加 {new: true}
才能获得更新的主题。这是一个重大错误。其次,我在 reducer 上的代码无法正常工作,因为我是新手,并且通过解决此类问题来学习。
我将 reducer 代码更改为:
case JOIN_TOPIC:
return {
allTopics: state.allTopics.map((eachTopic) =>
eachTopic._id === action.payload.topic._id
? action.payload.topic
: eachTopic
),
}
case LEAVE_TOPIC:
return {
allTopics: state.allTopics.map((eachTopic) =>
eachTopic._id === action.payload.topic._id
? action.payload.topic
: eachTopic
),
}
这基本上意味着,如果我有一个具有相同 _id 的主题,请将其替换为我一开始没有返回的新更新主题。
在此之后,一切开始顺利进行。很遗憾我认为问题是由于 useState
... 当它一直在我的数据库设置和 reducer 中...