【问题标题】:Using `react-apollo-hooks` and `useSubscription` hook使用 `react-apollo-hooks` 和 `useSubscription` 钩子
【发布时间】:2026-01-29 22:20:04
【问题描述】:

我正在使用 React、Apollo 和 react-apollo-hooks 构建一个简单的待办事项应用程序以支持钩子,但 useSubscription 钩子不会触发。

我知道实际的后端工作是有效的,因为我设置了一个 graphiql 应用程序,并且每当我保存待办事项时,todoCreated 事件就会出现在 graphiql 中。我也知道 websocket-setup 工作正常,因为查询和突变正在通过 websocket。顺便说一句,我正在使用 Elixir、Phoenix、Absinthe 作为后端的东西。

这是 Todo-app 组件:

import React, { useState } from 'react';
import gql from 'graphql-tag';
import { useQuery, useMutation, useSubscription } from 'react-apollo-hooks';

import styles from 'styles.css';

const TODO_FRAGMENT = gql`
  fragment TodoFields on Todo {
    id
    description
  }
`;

const GET_TODOS = gql`
  {
    todos {
      ...TodoFields
    }
  }
  ${TODO_FRAGMENT}
`;

const SAVE_TODO = gql`
  mutation createTodo($description: String!) {
    createTodo(description: $description) {
      ...TodoFields
    }
  }
  ${TODO_FRAGMENT}
`;

const DELETE_TODO = gql`
  mutation deleteTodo($id: ID!) {
    deleteTodo(id: $id) {
      id
    }
  }
`;

const NEW_TODO_SUBSCRIPTION = gql`
  subscription {
    todoCreated {
      ...TodoFields
    }
  }
  ${TODO_FRAGMENT}
`;

const Todos = () => {
  const [inputValue, setInputValue] = useState('');
  const { data, error, loading } = useQuery(GET_TODOS);

  const saveTodo = useMutation(SAVE_TODO, {
    update: (proxy, mutationResult) => {
      proxy.writeQuery({
        query: GET_TODOS,
        data: { todos: data.todos.concat([mutationResult.data.createTodo]) },
      });
    },
  });

  const deleteTodo = useMutation(DELETE_TODO, {
    update: (proxy, mutationResult) => {
      const id = mutationResult.data.deleteTodo.id
      proxy.writeQuery({
        query: GET_TODOS,
        data: { todos: data.todos.filter(item => item.id !== id) },
      });
    },
  });

  const subData = useSubscription(NEW_TODO_SUBSCRIPTION);
  console.log(subData);

  if (loading) {
    return <div>Loading...</div>;
  };

  if (error) {
    return <div>Error! {error.message}</div>;
  };

  return (
    <>
      <h1>Todos</h1>
      {data.todos.map((item) => (
        <div key={item.id} className={styles.item}>
          <button onClick={() => {
            deleteTodo({
              variables: {
                id: item.id,
              },
            });
          }}>Delete</button>
          {' '}
          {item.description}
        </div>
      ))}
      <input
        value={inputValue}
        onChange={(e) => setInputValue(e.target.value)}
        type="text"
      />
      <button onClick={() => {
        saveTodo({
          variables: {
            description: inputValue,
          },
        });
        setInputValue('');
      }}>Save</button>
    </>
  );
};

export default Todos;

这是根组件:

import React from 'react';
import { ApolloProvider } from 'react-apollo';
import { ApolloProvider as ApolloHooksProvider } from 'react-apollo-hooks';

import Todos from 'components/Todos';
import apolloClient from 'config/apolloClient';

const App = () => (
  <ApolloHooksProvider client={apolloClient}>
    <Todos />
  </ApolloHooksProvider>
);

export default App;

有人知道我做错了什么吗?

【问题讨论】:

    标签: reactjs react-apollo react-hooks absinthe


    【解决方案1】:

    对不起,我想通了,这是我的一个愚蠢的错误。问题似乎与我的 apolloClient 设置有关:

    import { split } from 'apollo-link';
    import { getMainDefinition } from 'apollo-utilities';
    import { ApolloClient } from 'apollo-client';
    import { InMemoryCache } from 'apollo-cache-inmemory';
    import { HttpLink } from 'apollo-link-http';
    import { onError } from 'apollo-link-error';
    import { ApolloLink } from 'apollo-link';
    
    import absintheSocketLink from 'config/absintheSocketLink';
    
    const apolloClient = new ApolloClient({
      link: ApolloLink.from([
        onError(({ graphQLErrors, networkError }) => {
          if (graphQLErrors)
            graphQLErrors.map(({ message, locations, path }) =>
              console.log(
                `[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`,
              ),
            );
          if (networkError) console.log(`[Network error]: ${networkError}`);
        }),
        split(
          // split based on operation type
          ({ query }) => {
            const definition = getMainDefinition(query);
            return (
              definition.kind === 'OperationDefinition' &&
              definition.operation === 'subscription'
            );
          },
          new HttpLink({
            uri: 'http://localhost:4000/api/graphql',
            credentials: 'same-origin'
          }),
          absintheSocketLink,
        ),
      ]),
      cache: new InMemoryCache()
    });
    
    export default apolloClient;
    

    上面代码中的错误是这一行

          absintheSocketLink,
    

    放错地方了。它应该在 HttpLink 之前。

    我傻了。

    【讨论】:

      【解决方案2】:

      我遇到了同样的问题,我的订阅总是发送空数据,而且我也犯了一个愚蠢的错误。

      【讨论】:

        最近更新 更多