微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

我怎样才能使它成为一个包含钩子的可调用 utils 函数?

如何解决我怎样才能使它成为一个包含钩子的可调用 utils 函数?

我目前正在使用 Apollo Client 的 useQueryuseMutation 钩子在几个不同的组件中执行相同的功能。我不想重复逻辑,而是想创建一个辅助函数,将逻辑保存在一个地方。

问题在于,useQueryuseMutation 是钩子意味着它们不能作为函数存在于单独的文件中,而是需要是有效的 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 钩子的名字。 useFollowUserfollowUseruseUnfollowUserunfollowUser

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 举报,一经查实,本站将立刻删除。