使用 `react-apollo-hooks` 和 `useSubscription` 钩子

Posted

技术标签:

【中文标题】使用 `react-apollo-hooks` 和 `useSubscription` 钩子【英文标题】:Using `react-apollo-hooks` and `useSubscription` hook 【发布时间】:2019-09-14 19:44:34 【问题描述】:

我正在使用 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;

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

【问题讨论】:

【参考方案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】:

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

【讨论】:

以上是关于使用 `react-apollo-hooks` 和 `useSubscription` 钩子的主要内容,如果未能解决你的问题,请参考以下文章

使用`react-apollo-hooks`和`useSubscription`钩子时如何避免“自动更新”缓存

React-Apollo-Hooks 使用Mutation 传递空变量?

将参数传递给 react-apollo-hooks useQuery

react-apollo-hooks 中的 useMutation 没有传递变量

仅在第一次以惯用方式和优雅方式呈现组件时执行 react-apollo-hooks useQuery

UseApolloClient 查询不会返回 fetchMore