如何解决我怎样才能使它成为一个包含钩子的可调用 utils 函数?
我目前正在使用 Apollo Client 的 useQuery
和 useMutation
钩子在几个不同的组件中执行相同的功能。我不想重复逻辑,而是想创建一个辅助函数,将逻辑保存在一个地方。
问题在于,useQuery
和 useMutation
是钩子意味着它们不能作为函数存在于单独的文件中,而是需要是有效的 React 函数组件。
我开始尝试制作一些实用的东西,但开始认为这可能无法完成。
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 函数?提前致谢!
在创建以下内容时,我收到了 "Invalid hook call. Hooks can only be called inside of the body of a function component."
,但我不知道为什么。
我认为这可能是由于在函数内部调用了 this,但我不知道如何避免这种情况。
export function useHandleFollow(props) {
const { user,isFollowingUser } = props
const [useFollowUser,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,onCompleted: setFollowSuccess(true)})
}
return followSuccess
}
当我立即在我的组件中调用它(而不是从函数内部调用)时,它会继续无限地重新渲染:
这是组件中一些更完整的代码
在 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 } from...
export function useHandleFollow(props) {
const { user,isFollowingUser } = props
const [followUser,followError }] = useMutation(FOLLOW_USER);
const [unfollowUser,setFollowSuccess] = useState(false)
if(!isFollowingUser){
followUser({ variables: { fromId: auth().currentUser.uid,onCompleted: () => setFollowSuccess(true)})
}else{
unfollowUser({ variables: { fromId: auth().currentUser.uid,onCompleted: () => setFollowSuccess(true)})
}
return [followSuccess]
}
解决方法
您可以创建一个 Custom Hook
来实现您的目标,方法是声明一个以 use
开头的函数,如下所示:
export function useHandleFollow (props) {
const [useFollowUser,{ followedData,followError }] = useMutation(FOLLOW_USER);
useFollowUser({ variables: { fromId: auth().currentUser.uid,toId: "userIDxyz"},onCompleted: props.handleUserFollow(user,isFollowingAuthor)})
}
请记住,所有 React Hooks Rule
也适用于 Custom Hooks
。
当然可以!您可以创建自己的自定义反应钩子。 React hooks 使用了一个相当简单的命名约定,“use-”前缀。
export function useHandleFollow(props) {
const [useFollowUser,followError }] = useMutation(
FOLLOW_USER
);
useFollowUser({
variables: { fromId: auth().currentUser.uid,toId: "userIDxyz" },isFollowingAuthor)
});
}
Only Call Hooks from React Functions
不要从常规 JavaScript 函数调用 Hook。相反,您可以:
- ✅ 从 React 函数组件调用 Hook。
- ✅ 调用 Hooks from 自定义 Hook(我们将在 on the next page 中了解它们)。
通过遵循此规则,您可以确保所有有状态的逻辑都在一个 组件在其源代码中清晰可见。
下一页是 Extracting a Custom Hook 部分!
自定义 Hook 是名称以“use”开头的 JavaScript 函数 这可能会调用其他 Hook。
编辑
仍然收到无效的钩子使用。
export function useHandleFollow(props) {
const { user,isFollowingUser } = props;
const [useFollowUser,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,onCompleted: setFollowSuccess(true)
});
}
return followSuccess;
}
我认为这里的问题是“mutate”函数的命名,你不方便地将它命名为另一个 React Hook。 React Hook linting 规则将 if (!isFollowingUser) {...}
解释为有条件地调用一个钩子,这是无效的。给他们一个非 React 钩子的名字。 useFollowUser
到 followUser
和 useUnfollowUser
到 unfollowUser
。
export function useHandleFollow(props) {
const { user,isFollowingUser } = props;
const [followUser,followError }] = useMutation(
FOLLOW_USER
);
const [unfollowUser,setFollowSuccess] = useState(false);
if (!isFollowingUser) {
followUser({
variables: { fromId: auth().currentUser.uid,onCompleted: setFollowSuccess(true)
});
} else {
unfollowUser({
variables: { fromId: auth().currentUser.uid,onCompleted: setFollowSuccess(true)
});
}
return followSuccess;
}
仍然呈现循环
useHandleFollow
在每个渲染周期被调用。我认为您的自定义钩子会在无条件更新每个逻辑分支中的 followSuccess
状态时触发渲染循环。
export function useHandleFollow(props) {
...
const [followSuccess,setFollowSuccess] = useState(false);
// setFollowSuccess(true) called always
if (!isFollowingUser) {
followUser({
variables: { fromId: auth().currentUser.uid,onCompleted: setFollowSuccess(true)
});
}
...
}
每次调用钩子时都会更新状态。您应该在希望此效果运行的时间设置条件,即将那个代码块放在 useEffect
钩子中,回调依赖于 isFollowingUser
。效果回调只会在 isFollowingUser
值更改时运行,而不是在组件呈现时运行。
export function useHandleFollow(props) {
const { user,setFollowSuccess] = useState(false);
useEffect(() => {
if (!isFollowingUser) {
followUser({
variables: { fromId: auth().currentUser.uid,onCompleted: setFollowSuccess(true)
});
} else {
unfollowUser({
variables: { fromId: auth().currentUser.uid,onCompleted: setFollowSuccess(true)
});
}
},[isFollowingUser]);
return followSuccess;
}
我是否应该返回一些东西,比如 set 方法或其他东西,以 接受新道具?否则,我如何最终调用钩子 那些新道具?
如果需要,您只需要从钩子返回更新程序函数。 React 钩子在每个渲染周期都会被调用,因此如果您将 props 传递给它们,那么它们将始终接收当前的 props。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。