如何使它成为包含钩子的可调用utils函数? [英] How can I make this a callable utils function that contains a hook?

查看:79
本文介绍了如何使它成为包含钩子的可调用utils函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在使用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)
  });
}

仅来自React Functions的呼叫挂钩

不要从常规JavaScript函数中调用Hook.相反,您可以:

  • ✅从React函数组件中调用钩子.
  • ✅来自的呼叫挂钩自定义挂钩(我们将在下一页 上了解它们).
  • >
  • ✅ 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆