如何在组件外部调用GraphQL

时间:2019-05-28 11:13:54

标签: reactjs graphql apollo

我已经使用查询组件制作了一堆React组件来调用GraphQL,并且一切正常。

在一个组件中,我需要从数据库中获取一些初始数据,但是没有任何可视化表示。

我尝试使用查询组件,但它似乎仅在渲染周期上被触发。我试图将其打包成一个函数,并在需要数据的组件中调用此函数。但是由于没有要显示的组件,因此未执行代码/查询。

如何在没有组件的情况下从数据库获取此数据?

我找不到有关如何解决此问题的任何文档。但是我不能 唯一这样做的人。

ApolloConsumer或ApolloProvider是我的问题的答案吗?

我正在开会和开会。会议进行了几天,每天都有很多会议。

我要实现的目标是每天渲染一个带有X个标签页的页面。每个标签都代表一天,并显示当天的会话次数。

我的会话页面:

    import React from 'react';
import FullWidthTabs from '../components/Sessions';
import SessionTab from '../components/SessionTab';
import BwAppBar2 from '../components/BwAppBar2';
import ConferenceDays from '../components/ConferenceDays';


class SessionsPage extends React.Component {

    static async getInitialProps() {
        console.log("GetInitProps SessionsPage");
    }

    render() {
        let a = ConferenceDays();
        return (

                <div>
                    <BwAppBar2 />
                    {a}
                     <FullWidthTabs days={['2018-06-11', '2018-06-12', '2018-06-13']} day1={ < SessionTab conferenceId = "57" day = '2018-06-11' / > } 
                                   day2={ < SessionTab conferenceId = "57" day = '2018-06-12' / > } day3={ < SessionTab conferenceId = "57" day = '2018-06-13' / > }>
                    </FullWidthTabs>
                </div>
                );
        }
}
export default (SessionsPage);

这里的日期已经硬编码在页面中,仅供测试。

但是要知道会议的间隔天数,我必须找到会议并确定开始和结束日期并生成介于两者之间的所有日期:

import React, { Component } from 'react'
import { graphql } from 'react-apollo'
import { Query } from 'react-apollo'
import gql from 'graphql-tag'
import Link from '@material-ui/core/Link';
import { useQuery } from "react-apollo-hooks";

import conferencesQuery from '../queries/conferences'
import { Table, Head, Cell } from './Table'
import ConferenceCard from './ConferenceCard';
import Grid from '@material-ui/core/Grid';
import Paper from '@material-ui/core/Paper';
import moment from 'moment';


const CONFERENCE_QUERY = gql`
 query conference($conferenceId : ID!){
      conference(id: $conferenceId){
          title
          start_date
          end_date
     }    
}
`
let index = 0;
let loopDate = 0;
let dates = [];
let conferenceId = 57;

const ConferenceDays = () => (
<Query query={CONFERENCE_QUERY} variables={{conferenceId}}>
    {({ loading, error, data }) => {
                        if (loading)
                            return <div>Fetching</div>
                        if (error)
                            return <div>Error</div>
                        const startDate = moment(data.conference.start_date, 'x');
                        const endDate = moment(data.conference.end_date, 'x');

                        for (loopDate = parseInt(data.conference.start_date);
                                loopDate < parseInt(data.conference.end_date);
                                loopDate += 86400000) {

                            let aDate = moment(loopDate, 'x');
                            dates.push(aDate.format('YYYY-MM-DD').toString());
                        }
                        console.log(dates);
                        return(dates);
                    }}
</Query>);

export default ConferenceDays

但是这种方法不正确吗?

在层次结构中提升ConferenceDates组件是否更正确?

7 个答案:

答案 0 :(得分:2)

您可以将ApolloClient的创建隔离到一个单独的文件中,并使用init函数来访问React组件之外的客户端。

import React from 'react';
import {
  ApolloClient,
  HttpLink,
  InMemoryCache,
} from "@apollo/client";

let apolloClient;

const httpLink = new HttpLink({
  uri: "http://localhost:4000/graphql",
  credentials: "same-origin",
});

function createApolloClient() {
  return new ApolloClient({
    link: httpLink,
    cache: new InMemoryCache(),
  });
}

export function initializeApollo() {
  const _apolloClient = apolloClient ?? createApolloClient();
  if (!apolloClient) apolloClient = _apolloClient;

  return _apolloClient;
}

export function useApollo() {
  const store = useMemo(() => initializeApollo(initialState), [initialState]);
  return store;
}

然后您将使用以下外部组件:

const client = initializeApollo()
const res = await client.query({
  query: MY_QUERY,
  variables: {},
})

我自己没有尝试过,但是我认为这是关于如何执行此操作以及如何访问ApolloClient的想法。

答案 1 :(得分:0)

您可以使用Apollo Api手动发送查询。参见Manually firing a query

答案 2 :(得分:0)

假设您已将应用程序包装在组件树顶部的ApolloProvider中,则可以使用withApollo HOC或ApolloConsumer获取查询实例:

const MyComponent = ({ client }) => {
 // await client.query(...)
}
withApollo(MyComponent)

<ApolloConsumer>
  {client => (
    // await client.query(...)
  )}
</ApolloConsumer>

客户实例exposes a variety of methods,例如querymutations,可分别用于向您的后端发送查询和变异。这使您可以轻松地使用组件内的任何生命周期方法或其他函数(例如事件处理程序)进行查询:

async onClick() {
  const { data } = await query({ query: MY_QUERY })
  ...
}

但是,请务必注意,这些调用会导致从服务器或缓存中进行一次提取-与使用Query组件不同,该组件实际上订阅了缓存中的更改,并且会在缓存更新时进行更新。

在大多数情况下,您仍然希望使用查询组件。 Query组件在挂载上运行其查询的事实不应被认为是一种限制-只是在组件树中为其找到正确位置的问题。通常,这仅意味着将其 up 提升到层次结构中,以便它包装需要查询数据的任何组件,然后将这些数据作为道具传递。在数据可用之前,您始终可以阻止您的组件实际呈现。

答案 3 :(得分:0)

如果您正在使用功能组件,则可以在函数中使用useApolloClient挂钩,就好像它不是挂钩。

import { useApolloClient, gql } from "@apollo/client";

 MY_QUERY = gql'
   query OUR_QUERY {
     books{
        edges{
           node{
             id
             title
             author
            }
         }
      }
   }
'

const myFunctionalComponent = () => {   // outside function component

    const client = useApolloClient();

    const aNormalFunction = () => {   // please note that this is not a component  
       client.query({
          query: MY_QUERY,
          fetchPolicy: "cache-first"   // select appropriate fetchPolicy
       }).then((data) => {
          console.log(data)   //do whatever you like with the data
       }).catch((err) => {
          console.log(err)
       })
    };

    // just call it as a function whenever you want
    aNormalFunction()    
    
    // you can even call it conditionally which is not possible with useQuery hook
    if (true) {
        aNormalFunction()
    }

    return (
        <p>Hello Hook!</>
    );
};

export default myFunctionalComponent;

答案 4 :(得分:0)

在 React 组件中,您可以使用 useLazyQuery from Apollo Client,它只会在您调用它时触发。然后将它传递给您的函数并在那里调用它。

答案 5 :(得分:0)

ApolloClient 有一个 mutate 方法。您只需导入 Apollo 客户端实例并调用 apolloClient.mutate

答案 6 :(得分:0)

对于使用 urql 作为 GraphQL 客户端的人-

const graphqlClient = createClient({
  url: '',
  fetchOptions: () => {
    return {
      headers: {  }
    };
  }
});

const fetchCountries = () => (dispatch: Dispatch) => {
  graphqlClient
    .query(countriesQuery, getCountriesVariable())
    .toPromise()
    .then(result => {
      dispatch({
        type: UPDATE_COUNTRIES,
        payload: result.data.countries
      });
      if (result.error?.message) {
        // https://formidable.com/open-source/urql/docs/basics/errors/
        logErrorMessage(result.error?.message, 'AppActions.fetchCountries');
      }
    })
    .catch(error => {
      logError(error, 'AppActions.fetchCountries');
    });
};

文档:https://formidable.com/open-source/urql/docs/api/core/#clientquery