[英]How to re-render a custom hook after initial render
I have custom hook named useIsUserSubscribed
that checks to see a specific user is subscribed.我有一个名为
useIsUserSubscribed
的自定义钩子,它检查是否订阅了特定用户。 It returns true if the user is subscribed and false if the user is not subscribed...如果用户已订阅,则返回 true,如果用户未订阅,则返回 false...
import { useState, useEffect } from "react";
import { useSelector } from "react-redux";
import { checkSubscription } from "../services";
// this hook checks if the current user is subscribed to a particular user(publisherId)
function useIsUserSubscribed(publisherId) {
const [userIsSubscribed, setUserIsSubscribed] = useState(null);
const currentUserId = useSelector((state) => state.auth.user?.id);
useEffect(() => {
if (!currentUserId || !publisherId) return;
async function fetchCheckSubscriptionData() {
try {
const res = await checkSubscription(publisherId);
setUserIsSubscribed(true);
} catch (err) {
setUserIsSubscribed(false);
}
}
fetchCheckSubscriptionData();
}, [publisherId, currentUserId]);
return userIsSubscribed;
}
export default useIsUserSubscribed;
...I have a button using this hook that renders text conditionally based on the boolean returned from useIsUserSubscribed
... ...我有一个使用此挂钩的按钮,它根据从 useIsUserSubscribed 返回的
useIsUserSubscribed
有条件地呈现文本...
import React, { useEffect, useState } from "react";
import { add, remove } from "../../services";
import useIsUserSubscribed from "../../hooks/useIsUserSubscribed";
const SubscribeUnsubscribeBtn = ({profilePageUserId}) => {
const userIsSubscribed = useIsUserSubscribed(profilePageUserId);
const onClick = async () => {
if (userIsSubscribed) {
// this is an API Call to the backend
await removeSubscription(profilePageUserId);
} else {
// this is an API Call to the backend
await addSubscription(profilePageUserId);
}
// HOW CAN I RERENDER THE HOOK HERE!!!!?
}
return (
<button type="button" className="sub-edit-unsub-btn bsc-button" onClick={onClick}>
{userIsSubscribed ? 'Subscribed' : 'Unsubscribed'}
</button>
);
}
After onClick
I would like to rerender my the useIsUserSubscribed
hook So that my button text toggles.在
onClick
之后,我想重新渲染我的useIsUserSubscribed
钩子,以便我的按钮文本切换。 Can this be done?这可以做到吗?
Add a dependece on useIsUserSubscribed's useEffect.添加对useIsUserSubscribed 的useEffect 的依赖。
hook:钩:
function useIsUserSubscribed(publisherId) {
const [userIsSubscribed, setUserIsSubscribed] = useState(null);
const currentUserId = useSelector((state) => state.auth.user?.id);
// add refresh dependece
const refresh = useSelector((state) => state.auth.refresh);
useEffect(() => {
...
}, [publisherId, currentUserId, refresh]);
...
}
component:零件:
const onClick = async () => {
...
// HOW CAN I RERENDER THE HOOK HERE!!!!?
// when click, you can dispatch a refresh flag.
dispatch(refreshSubState([]))
}
Expose forceUpdate metheod.公开 forceUpdate 方法。
hook:钩:
function useIsUserSubscribed(publisherId) {
const [update, setUpdate] = useState({});
const forceUpdate = () => {
setUpdate({});
}
return {userIsSubscribed, forceUpdate};
}
component:零件:
const {userIsSubscribed, forceUpdate} = useIsUserSubscribed(profilePageUserId);
const onClick = async () => {
...
forceUpdate();
}
you can not use useEffect in your hook for that purpose try this:你不能为此目的在你的钩子中使用 useEffect 试试这个:
hook:钩:
function useIsUserSubscribed() {
const currentUserId = useSelector((state) => state.auth.user?.id);
const checkUser = useCallback(async (publisherId, setUserIsSubscribed) => {
if (!currentUserId || !publisherId) return;
try {
const res = await checkSubscription(publisherId);
setUserIsSubscribed(true);
} catch (err) {
setUserIsSubscribed(false);
}
}, [currentUserId]);
return {checkUser};
}
export default useIsUserSubscribed;
component:零件:
const SubscribeUnsubscribeBtn = ({profilePageUserId}) => {
const [userIsSubscribed,setUserIsSubscribed]=useState(false);
const { checkUser } = useIsUserSubscribed();
useEffect(()=>{
checkUser(profilePageUserId,setUserIsSubscribed)
},[checkUser,profilePageUserId]);
const onClick = async () => {
if (userIsSubscribed) {
// this is an API Call to the backend
await removeSubscription(profilePageUserId);
} else {
// this is an API Call to the backend
await addSubscription(profilePageUserId);
}
// HOW CAN I RERENDER THE HOOK HERE!!!!?
checkUser(profilePageUserId,setUserIsSubscribed)
}
return (
<button type="button" className="sub-edit-unsub-btn bsc-button" onClick={onClick}>
{userIsSubscribed ? 'Subscribed' : 'Unsubscribed'}
</button>
);
}
you can also add some loading state in your hook and return them too so you can check if process is already done or not您还可以在您的钩子中添加一些加载 state 并将它们也返回,这样您就可以检查过程是否已经完成
Here is another solution by user @bitspook这是用户@bitspook 的另一个解决方案
SubscribeUnsubscribeBtn
has a dependency on useIsUserSubscribed
, but useIsUserSubscribed
don't depend on anything from SubscribeUnsubscribeBtn
. SubscribeUnsubscribeBtn
依赖于useIsUserSubscribed
,但useIsUserSubscribed
不依赖于SubscribeUnsubscribeBtn
中的任何内容。 Instead, useIsUserSubscribed
is keeping a local state.相反,
useIsUserSubscribed
保留了本地 state。 You have a couple of choices here:您在这里有几个选择:
useIsUserSubscribed
that you need to change its internal state.useIsUserSubscribed
需要更改其内部state。 For 1)
对于
1)
const [userIsSubscribed, setUserIsSubscribed] = useState(null);
move this state to Redux store and use it with useSelector.将此 state 移动到 Redux 存储并与 useSelector 一起使用。
For 2)
, return an array of value and callback from the hook, instead of just the value.对于
2)
,从钩子返回一个值和回调数组,而不仅仅是值。 It will allow you to communicate from component back into the hook.它将允许您从组件通信回钩子。
In useIsUserSubscribed
,在
useIsUserSubscribed
中,
return [userIsSubscribed, setUserIsSubscribed];
Then in onClick
, you can call setUserIsSubscribed(false)
, changing the hook's internal state, and re-rendering your component.然后在
onClick
中,您可以调用setUserIsSubscribed(false)
,更改钩子的内部 state 并重新渲染您的组件。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.