【问题标题】:Stop `useMutation` from re-rendering component and ignore result停止“useMutation”重新渲染组件并忽略结果
【发布时间】:2021-11-02 16:08:31
【问题描述】:

我有一个这样的突变(这不是实际的突变调用,而是一个最小的例子):

const App = () => {
  const [myMutation] = useMutation(gql`
    mutation Test($updateUserId: ID!, $updateUserInput: UpdateUserInput!) {
      updateUser(id: $updateUserId, input: $updateUserInput) {
        id
        firstname
        age
      }
    }
  `);

  // Runs every time this component is rendered
  console.log("rendered");

  // Called when the button is clicked
  const update = () => {
    myMutation({
      variables: {
        updateUserId: 1,
        updateUserInput: {
          age: Math.round(Math.random() * 10 + 5) // Set a random age from 5 - 15
        }
      }
    });
  };

  return (
    <>
      <h1>Update Test</h1>
      <button onClick={update}>Update!</button>
    </>
  );
};

每当调用onClick 时,都会重新渲染整个组件。这不是我想要的,因为我不关心突变的结果。有什么办法可以阻止myMutation 导致重新渲染,并完全忽略结果?

【问题讨论】:

  • 通常,useMutation 不会触发重新渲染,直到您订阅了缓存中的某些值。
  • @RyanLe 你这是什么意思?能举个例子吗?
  • 我需要了解您应用的大局。你有你的仓库的链接吗?
  • @RyanLe 抱歉,我的仓库没有链接。是否可以使用 CodeSandbox 或类似的东西来演示它?如果您需要的话,我也可以尝试制作我的程序如何工作的基本框架。
  • 当然可以。你可以尝试通过codesanbox重现它。我会直接跳进去。

标签: reactjs apollo apollo-client


【解决方案1】:

这可能是因为突变返回了一个规范化的对象,该组件或更高的组件通过 useQuery 之类的钩子依赖该对象。

如果您不关心突变的结果,请确保它不会返回标准化对象。

类似

mutation SomeMutation ($input: SomeMutationInput!){
  someMutation (input: $input){
    ok
  }
}

【讨论】:

【解决方案2】:

useMutation 是一个钩子,其中有 state 导致重新渲染

请参阅下面的useMultation 类型:

export interface MutationResult<TData = any> {
    data?: TData | null;
    error?: ApolloError;
    loading: boolean;
    called: boolean;
    client: ApolloClient<object>;
}

loading 状态是导致重新渲染的状态,因此您在哪个组件中删除 useMutation 它将由于 state 而重新渲染


一种可能的解决方法是将带有useMutation 的组件与另一个组件分开

类似这样的:

function App() {
  return (
    <>
      <Header />  // <-- this coponent won't re-render
      <UpdateUserButton />  // <-- useMutation is in here!
    </>
  );
}

查看实时示例:

【讨论】:

  • 哦,我明白了。不过,有没有办法让Header 停止更新?我听说过React.memo 等,但我不知道它们是如何工作的。无论如何感谢您的回答!
  • 加载是state,所以我认为这是不可能的。为特定操作分离组件也是“分离关注点”的最佳实践。
  • 如果您认为某个答案有用,您可以投票或将其标记为接受,并将其突出显示给其他需要的人。
  • 抱歉,我知道我能做到,我必须按照我的评论去做。非常感谢您的回答!
  • 谢谢!,这意味着很多
【解决方案3】:

好吧,如果您不需要突变返回的data,您也可以传递ignoreResults 选项。突变钩子不会返回数据,但 loading 不会调用这两者,这会阻止重新渲染。

https://www.apollographql.com/docs/react/data/mutations/#ignoreresults

const [someMutation] = useSomeMutation({
 ignoreResults: true,
});

【讨论】:

    【解决方案4】:

    以下应该可以工作(未经测试)

    • 由于您不想重新渲染,因此无需使用具有状态的 useMutation 挂钩。
    • 相反,您可以直接导入您的 apollo-client 并在其上使用 mutate,而无需使用 useMutation 挂钩。
    • 您可以选择在 .then 函数中使用结果或去掉它。
    import { apolloClient } from '../yourApolloClientFile';
    
    
    const App = () => {
    
      const myMutation = (vars) => apolloClient.mutate({
        mutation: gql`
            mutation Test($updateUserId: ID!, $updateUserInput: UpdateUserInput!) {
              updateUser(id: $updateUserId, input: $updateUserInput) {
                id
                firstname
                age
              }
            }
          `,
        variables: vars
      })
        .then(result => console.log(result))
        .catch(error => console.log(error))
    
    
      // Runs every time this component is rendered
      console.log("rendered");
    
      // Called when the button is clicked
      const update = () => {
        myMutation({
          updateUserId: 1,
          updateUserInput: {
            age: Math.round(Math.random() * 10 + 5) // Set a random age from 5 - 15
          }
        });
      };
    
      return (
        <>
          <h1>Update Test</h1>
          <button onClick={update}>Update!</button>
        </>
      );
    };
    
    

    【讨论】:

      猜你喜欢
      • 2021-06-20
      • 1970-01-01
      • 2020-12-07
      • 1970-01-01
      • 1970-01-01
      • 2021-01-07
      • 2021-12-05
      • 2019-04-18
      • 2019-12-01
      相关资源
      最近更新 更多