如何使它成为包含钩子的可调用utils函数? [英] How can I make this a callable utils function that contains a hook?
问题描述
我目前正在使用Apollo Client的 useQuery
和 useMutation
挂钩在几个不同的组件中执行相同的功能.我不想创建重复的逻辑,而是想创建一个可以将逻辑保持在单个位置的辅助函数.
I'm currently using Apollo Client's useQuery
and useMutation
hooks to perform the same function in several different components. Instead of repeating the logic, I would like to create a helper function that can keep the logic in a single place.
问题在于, useQuery
和 useMutation
被钩子表示它们不能仅仅作为函数存在于单独的文件中,而是需要有效的React函数组件.
The problem with this, is useQuery
and useMutation
being hooks mean they can't just live in a separate file as functions, but instead need to be valid React function components.
我开始尝试使某些功能正常运行,但开始认为这可能无法完成.
I started trying to make something functional but starting to think this might not be able to be done.
export function HandleFollow (props) {
const [useFollowUser, { followedData, followError }] = useMutation(FOLLOW_USER);
useFollowUser({ variables: { fromId: auth().currentUser.uid, toId: "userIDxyz"}, onCompleted: props.handleUserFollow(user, isFollowingAuthor)})
}
是否可以在React Hooks中使用util/helper函数?预先感谢!
Is it possible to use util/helper functions with React Hooks? Thanks in advance!
创建以下内容时,我收到"无效的挂接调用.只能在函数组件的主体内部调用挂钩."
,我不知道为什么.
When creating the below, I'm receiving "Invalid hook call. Hooks can only be called inside of the body of a function component."
and I can't figure out why.
我认为这可能是由于从函数内部调用此方法引起的,但我不知道如何避免这种情况.
I think that may be due to calling this from inside a function, but I can't figure out how to avoid that.
export function useHandleFollow(props) {
const { user, isFollowingUser } = props
const [useFollowUser, { followedData, followError }] = useMutation(FOLLOW_USER);
const [useUnfollowUser, { unfollowedData, unfollowedError }] = useMutation(UNFOLLOW_USER);
const [followSuccess, setFollowSuccess] = useState(false)
if(!isFollowingUser){
useFollowUser({ variables: { fromId: auth().currentUser.uid, toId: user.id}, onCompleted: setFollowSuccess(true)})
}else{
useUnfollowUser({ variables: { fromId: auth().currentUser.uid, toId: user.id}, onCompleted: setFollowSuccess(true)})
}
return followSuccess
}
当我在组件中立即调用此函数(而不是从函数内部调用)时,它将继续无限地重新渲染:
And when I call this right away in my component (instead of calling from inside a function), it continues to infinitely re-render:
这是该组件中一些更完整的代码
Here's some more complete code from the component
在Home.js中:
const followed = useHandleFollow({ user: author, isFollowingAuthor })
export default posts = (props) =>{
let { post, excludeUser = false } = props
let { author } = post
let { date, things, isFollowingAuthor } = post
let { profile_picture } = author
let currentUser = auth().currentUser
const [followed] = useHandleFollow({ user: author, isFollowingAuthor })
return ()
}
这是在follow.js中,我正在将其作为 import {useHandleFollow}从...导入...
And this is in follow.js, which I'm importing as import { useHandleFollow } from...
export function useHandleFollow(props) {
const { user, isFollowingUser } = props
const [followUser, { followedData, followError }] = useMutation(FOLLOW_USER);
const [unfollowUser, { unfollowedData, unfollowedError }] = useMutation(UNFOLLOW_USER);
const [followSuccess, setFollowSuccess] = useState(false)
if(!isFollowingUser){
followUser({ variables: { fromId: auth().currentUser.uid, toId: user.id}, onCompleted: () => setFollowSuccess(true)})
}else{
unfollowUser({ variables: { fromId: auth().currentUser.uid, toId: user.id}, onCompleted: () => setFollowSuccess(true)})
}
return [followSuccess]
}
推荐答案
当然是!您可以创建自己的自定义react挂钩.React挂钩使用相当简单的命名约定,即"use-".前缀.
Of course it is! You can create your own custom react hooks. React hooks use a rather simple naming convention, "use-" prefix.
export function useHandleFollow(props) {
const [useFollowUser, { followedData, followError }] = useMutation(
FOLLOW_USER
);
useFollowUser({
variables: { fromId: auth().currentUser.uid, toId: "userIDxyz" },
onCompleted: props.handleUserFollow(user, isFollowingAuthor)
});
}
不要从常规JavaScript函数中调用Hook.相反,您可以:
- ✅ Call Hooks from React function components.
- ✅ Call Hooks from custom Hooks (we’ll learn about them on the next page).
通过遵循此规则,您可以确保组件从其源代码中清晰可见.
By following this rule, you ensure that all stateful logic in a component is clearly visible from its source code.
在下一页上是提取自定义挂钩部分!
自定义钩子是一种JavaScript函数,其名称以"use"开头并且可能会称为其他挂钩.
编辑
仍然收到无效的钩子用法.
Still receiving invalid hook usage.
export function useHandleFollow(props) {
const { user, isFollowingUser } = props;
const [useFollowUser, { followedData, followError }] = useMutation(
FOLLOW_USER
);
const [useUnfollowUser, { unfollowedData, unfollowedError }] = useMutation(
UNFOLLOW_USER
);
const [followSuccess, setFollowSuccess] = useState(false);
if (!isFollowingUser) {
useFollowUser({
variables: { fromId: auth().currentUser.uid, toId: user.id },
onCompleted: setFollowSuccess(true)
});
} else {
useUnfollowUser({
variables: { fromId: auth().currentUser.uid, toId: user.id },
onCompleted: setFollowSuccess(true)
});
}
return followSuccess;
}
我认为这里的问题是"mutate"的命名.函数,就像另一个React Hook一样,您不方便地对其进行了命名.React Hook linting规则将 if(!isFollowingUser){...}
解释为有条件地调用一个invald的钩子.给他们一个非反应钩的名字.将 useFollowUser
更改为 followUser
,将 useUnfollowUser
更改为 unfollowUser
.
I think the issue here is the naming of the "mutate" function, which you've inconveniently named just like another React Hook. The React Hook linting rules are interpreting the if (!isFollowingUser) {...}
as conditionally calling a hook, which is invald. Give them a non-React-hook name. useFollowUser
to followUser
and useUnfollowUser
to unfollowUser
.
export function useHandleFollow(props) {
const { user, isFollowingUser } = props;
const [followUser, { followedData, followError }] = useMutation(
FOLLOW_USER
);
const [unfollowUser, { unfollowedData, unfollowedError }] = useMutation(
UNFOLLOW_USER
);
const [followSuccess, setFollowSuccess] = useState(false);
if (!isFollowingUser) {
followUser({
variables: { fromId: auth().currentUser.uid, toId: user.id },
onCompleted: setFollowSuccess(true)
});
} else {
unfollowUser({
variables: { fromId: auth().currentUser.uid, toId: user.id },
onCompleted: setFollowSuccess(true)
});
}
return followSuccess;
}
静态渲染循环
每个渲染周期都会调用
useHandleFollow
.我认为您的自定义钩子会在无条件更新逻辑的每个分支中的 followSuccess
状态时触发渲染循环.
useHandleFollow
is called each render cycle. I think your custom hook triggers the render looping when it is unconditionally updating the followSuccess
state in each branch of logic.
export function useHandleFollow(props) {
...
const [followSuccess, setFollowSuccess] = useState(false);
// setFollowSuccess(true) called always
if (!isFollowingUser) {
followUser({
variables: { fromId: auth().currentUser.uid, toId: user.id },
onCompleted: setFollowSuccess(true)
});
} else {
unfollowUser({
variables: { fromId: auth().currentUser.uid, toId: user.id },
onCompleted: setFollowSuccess(true)
});
}
...
}
这最终会在每次调用该挂钩时更新状态 .您应在何时希望运行此效果时设置条件,即将 that 代码块放置在 useEffect
钩子上,并具有对 isFollowingUser
.效果回调仅在 isFollowingUser
值更改时运行,而不在组件呈现时运行.
This ends up updating state every time the hook is called. You should place a condition on when you want this effect to be run, i.e. place that code block in an useEffect
hook with a callback dependency on isFollowingUser
. The effect callback will only run when the isFollowingUser
value changes, not whenever the component renders.
export function useHandleFollow(props) {
const { user, isFollowingUser } = props;
const [followUser, { followedData, followError }] = useMutation(
FOLLOW_USER
);
const [unfollowUser, { unfollowedData, unfollowedError }] = useMutation(
UNFOLLOW_USER
);
const [followSuccess, setFollowSuccess] = useState(false);
useEffect(() => {
if (!isFollowingUser) {
followUser({
variables: { fromId: auth().currentUser.uid, toId: user.id },
onCompleted: setFollowSuccess(true)
});
} else {
unfollowUser({
variables: { fromId: auth().currentUser.uid, toId: user.id },
onCompleted: setFollowSuccess(true)
});
}
}, [isFollowingUser]);
return followSuccess;
}
我是否应该将诸如set方法之类的东西返回给接受新道具?否则,我最终如何用那些新道具?
Should I be returning something, like a set method or something, to accept new props? Otherwise, how do I end up calling the hook with those new props?
仅在需要时才需要从钩子返回updater函数.React挂钩在每个渲染周期都被称为,因此,如果您将道具传递给它们,那么它们将始终接收当前的道具.
You only need to return updater function from hooks if you need them. React hooks are called each render cycle, so if you pass props to them then they will always receive the current props.
这篇关于如何使它成为包含钩子的可调用utils函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!