Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Reactjs 接下来使用apollo,SSR不起作用,请求在客户端完成_Reactjs_Next.js_Apollo Client - Fatal编程技术网

Reactjs 接下来使用apollo,SSR不起作用,请求在客户端完成

Reactjs 接下来使用apollo,SSR不起作用,请求在客户端完成,reactjs,next.js,apollo-client,Reactjs,Next.js,Apollo Client,我有很短的代码,我正在尝试使用,接下来是apolo。 但是SSR在我的情况下不起作用,我还在打客户电话,也许有人可以指导我 我的阿波罗之旅-> import withApollo from "next-with-apollo"; import ApolloClient, { InMemoryCache } from "apollo-boost"; import { ApolloProvider } from "@apollo/react-hook

我有很短的代码,我正在尝试使用,接下来是apolo。 但是SSR在我的情况下不起作用,我还在打客户电话,也许有人可以指导我

我的阿波罗之旅->

import withApollo from "next-with-apollo";
import ApolloClient, { InMemoryCache } from "apollo-boost";
import { ApolloProvider } from "@apollo/react-hooks";

export default withApollo(
  ({ initialState }) => {
    return new ApolloClient({
      uri: "http://localhost:4000/graphql",
      credentials: "include",
      cache: new InMemoryCache().restore(initialState || {}),
    });
  },
  {
    render: ({ Page, props }) => {
      return (
        <ApolloProvider client={props.apollo}>
          <Page {...props} />
        </ApolloProvider>
      );
    },
  }
);
从“阿波罗下一步”导入阿波罗;
从“apollo boost”导入apollo客户端,{InMemoryCache};
从“@apollo/react hooks”导入{apollo provider}”;
使用Apollo导出默认值(
({initialState})=>{
返回新客户端({
uri:“http://localhost:4000/graphql",
证书:“包括”,
缓存:新建InMemoryCache().restore(初始状态| |{}),
});
},
{
呈现:({Page,props})=>{
返回(
);
},
}
);
而页面本身

import gql from "graphql-tag";
import { useQuery } from "@apollo/react-hooks";
import withApollo from "../../HOC/withApollo";
import { getDataFromTree } from "@apollo/react-ssr";

const QUERY = gql`
  {
    me {
      user {
        email
      }
    }
  }
`;

const Profile = () => {
  const { data } = useQuery(QUERY);

  console.log(data);

  return <div>{data?.me.user?.email}</div>;
};

export default withApollo(Profile, { getDataFromTree });
从“graphql标签”导入gql;
从“@apollo/react hooks”导入{useQuery}”;
从“../../HOC/withApollo”导入withApollo;
从“@apollo/react-ssr”导入{getDataFromTree}”;
const QUERY=gql`
{
我{
使用者{
电子邮件
}
}
}
`;
常量配置文件=()=>{
const{data}=useQuery(查询);
控制台日志(数据);
返回{data?.me.user?.email};
};
使用Apollo导出默认值(配置文件,{getDataFromTree});

但是请求仍在客户端执行。

请求在客户端被调用,因为您已经编写了
const{data}=useQuery(查询)。所以,当组件在客户端呈现时,就会调用该查询

如果只想在服务器端(即ssr)调用该查询,则使用
getServerSideProps
方法,在该方法中调用给定的查询,并将结果作为props传递给概要文件组件

例如:

const Profile = ({ data }) => {
  // Render data...
}

// This gets called on every request
export async function getServerSideProps() {
  // Fetch data from external API
  const res = await fetch(`https://.../data`)
  const data = await res.json()

  // Pass data to the page via props
  return { props: { data } }
}

export default Profile; 
注意:您可以导入顶级作用域中的模块,以便在getServerSideProps中使用。getServerSideProps中使用的导入不会绑定到客户端。
这意味着您可以直接在getServerSideProps中编写服务器端代码。这包括从文件系统或数据库读取数据。

这是我正在使用的解决方案。它允许在HOC中包装页面(主要组件),然后发出请求ssr或notssr

src
│   
│      
│
└───pages
│   │   _app.tsx
│   │   _document.tsx
|   |   index.tsx
│   │
│   |
└───apollo
    │   withApollo.ts
    │   createWithApollo.tsx
createWithApollo.tsx

import React from "react";
import App from "next/app";
import Head from "next/head";
import { ApolloProvider } from "@apollo/client";

// On the client, we store the Apollo Client in the following variable.
// This prevents the client from reinitializing between page transitions.
let globalApolloClient: any = null;

/**
 * Installs the Apollo Client on NextPageContext
 * or NextAppContext. Useful if you want to use apolloClient
 * inside getStaticProps, getStaticPaths or getServerSideProps
 * @param {NextPageContext | NextAppContext} ctx
 */
export const initOnContext = (ac: any, ctx: any) => {
  const inAppContext = Boolean(ctx.ctx);

  // We consider installing `withApollo({ ssr: true })` on global App level
  // as antipattern since it disables project wide Automatic Static Optimization.
  if (process.env.NODE_ENV === "development") {
    if (inAppContext) {
      console.warn(
        "Warning: You have opted-out of Automatic Static Optimization due to `withApollo` in `pages/_app`.\n" +
          "Read more: https://err.sh/next.js/opt-out-auto-static-optimization\n"
      );
    }
  }

  // Initialize ApolloClient if not already done
  const apolloClient =
    ctx.apolloClient ||
    initApolloClient(ac, ctx.apolloState || {}, inAppContext ? ctx.ctx : ctx);

  // We send the Apollo Client as a prop to the component to avoid calling initApollo() twice in the server.
  // Otherwise, the component would have to call initApollo() again but this
  // time without the context. Once that happens, the following code will make sure we send
  // the prop as `null` to the browser.
  apolloClient.toJSON = () => null;

  // Add apolloClient to NextPageContext & NextAppContext.
  // This allows us to consume the apolloClient inside our
  // custom `getInitialProps({ apolloClient })`.
  ctx.apolloClient = apolloClient;
  if (inAppContext) {
    ctx.ctx.apolloClient = apolloClient;
  }

  return ctx;
};

/**
 * Always creates a new apollo client on the server
 * Creates or reuses apollo client in the browser.
 * @param  {NormalizedCacheObject} initialState
 * @param  {NextPageContext} ctx
 */
const initApolloClient = (apolloClient: any, initialState: any, ctx: any) => {
  // Make sure to create a new client for every server-side request so that data
  // isn't shared between connections (which would be bad)
  if (typeof window === "undefined") {
    return createApolloClient(apolloClient(ctx), initialState, ctx);
  }

  // Reuse client on the client-side
  if (!globalApolloClient) {
    globalApolloClient = createApolloClient(
      apolloClient(ctx),
      initialState,
      ctx
    );
  }

  return globalApolloClient;
};

/**
 * Creates a withApollo HOC
 * that provides the apolloContext
 * to a next.js Page or AppTree.
 * @param  {Object} withApolloOptions
 * @param  {Boolean} [withApolloOptions.ssr=false]
 * @returns {(PageComponent: ReactNode) => ReactNode}
 */
export const createWithApollo = (ac: any) => {
  return ({ ssr = false } = {}) => (PageComponent: any) => {
    const WithApollo = ({ apolloClient, apolloState, ...pageProps }: any) => {
      let client;
      if (apolloClient) {
        // Happens on: getDataFromTree & next.js ssr
        client = apolloClient;
      } else {
        // Happens on: next.js csr
        client = initApolloClient(ac, apolloState, undefined);
      }

      return (
        <ApolloProvider client={client}>
          <PageComponent {...pageProps} />
        </ApolloProvider>
      );
    };

    // Set the correct displayName in development
    if (process.env.NODE_ENV !== "production") {
      const displayName =
        PageComponent.displayName || PageComponent.name || "Component";
      WithApollo.displayName = `withApollo(${displayName})`;
    }

    if (ssr || PageComponent.getInitialProps) {
      WithApollo.getInitialProps = async (ctx: any) => {
        const inAppContext = Boolean(ctx.ctx);
        const { apolloClient } = initOnContext(ac, ctx);

        // Run wrapped getInitialProps methods
        let pageProps = {};
        if (PageComponent.getInitialProps) {
          pageProps = await PageComponent.getInitialProps(ctx);
        } else if (inAppContext) {
          pageProps = await App.getInitialProps(ctx);
        }

        // Only on the server:
        if (typeof window === "undefined") {
          const { AppTree } = ctx;
          // When redirecting, the response is finished.
          // No point in continuing to render
          if (ctx.res && ctx.res.finished) {
            return pageProps;
          }

          // Only if dataFromTree is enabled
          if (ssr && AppTree) {
            try {
              // Import `@apollo/react-ssr` dynamically.
              // We don't want to have this in our client bundle.
              const { getDataFromTree } = await import(
                "@apollo/client/react/ssr"
              );

              // Since AppComponents and PageComponents have different context types
              // we need to modify their props a little.
              let props;
              if (inAppContext) {
                props = { ...pageProps, apolloClient };
              } else {
                props = { pageProps: { ...pageProps, apolloClient } };
              }

              // Take the Next.js AppTree, determine which queries are needed to render,
              // and fetch them. This method can be pretty slow since it renders
              // your entire AppTree once for every query. Check out apollo fragments
              // if you want to reduce the number of rerenders.
              // https://www.apollographql.com/docs/react/data/fragments/
              await getDataFromTree(<AppTree {...props} />);
            } catch (error) {
              // Prevent Apollo Client GraphQL errors from crashing SSR.
              // Handle them in components via the data.error prop:
              // https://www.apollographql.com/docs/react/api/react-apollo.html#graphql-query-data-error
              console.error("Error while running `getDataFromTree`", error);
            }

            // getDataFromTree does not call componentWillUnmount
            // head side effect therefore need to be cleared manually
            Head.rewind();
          }
        }

        return {
          ...pageProps,
          // Extract query data from the Apollo store
          apolloState: apolloClient.cache.extract(),
          // Provide the client for ssr. As soon as this payload
          // gets JSON.stringified it will remove itself.
          apolloClient: ctx.apolloClient,
        };
      };
    }

    return WithApollo;
  };
};

function createApolloClient(apolloClient: any, initialState: any, ctx: any) {
  // The `ctx` (NextPageContext) will only be present on the server.
  // use it to extract auth headers (ctx.req) or similar.
  apolloClient.ssrMode = Boolean(ctx);
  apolloClient.cache.restore(initialState);

  return apolloClient;
}
   import Router from "next/router";
    import { AppProps } from "next/app";

    
  
    
    function MyApp({ Component, pageProps }: AppProps) {
 
    
      return (
          <Component {...pageProps} /> 
      );
    }
    
    export default MyApp;
import React from "react";
import { withApollo } from "../apollo/withApollo";


const Index = () => <div></div>;

export default withApollo({ ssr: true })(Index);
\u app.tsx

import React from "react";
import App from "next/app";
import Head from "next/head";
import { ApolloProvider } from "@apollo/client";

// On the client, we store the Apollo Client in the following variable.
// This prevents the client from reinitializing between page transitions.
let globalApolloClient: any = null;

/**
 * Installs the Apollo Client on NextPageContext
 * or NextAppContext. Useful if you want to use apolloClient
 * inside getStaticProps, getStaticPaths or getServerSideProps
 * @param {NextPageContext | NextAppContext} ctx
 */
export const initOnContext = (ac: any, ctx: any) => {
  const inAppContext = Boolean(ctx.ctx);

  // We consider installing `withApollo({ ssr: true })` on global App level
  // as antipattern since it disables project wide Automatic Static Optimization.
  if (process.env.NODE_ENV === "development") {
    if (inAppContext) {
      console.warn(
        "Warning: You have opted-out of Automatic Static Optimization due to `withApollo` in `pages/_app`.\n" +
          "Read more: https://err.sh/next.js/opt-out-auto-static-optimization\n"
      );
    }
  }

  // Initialize ApolloClient if not already done
  const apolloClient =
    ctx.apolloClient ||
    initApolloClient(ac, ctx.apolloState || {}, inAppContext ? ctx.ctx : ctx);

  // We send the Apollo Client as a prop to the component to avoid calling initApollo() twice in the server.
  // Otherwise, the component would have to call initApollo() again but this
  // time without the context. Once that happens, the following code will make sure we send
  // the prop as `null` to the browser.
  apolloClient.toJSON = () => null;

  // Add apolloClient to NextPageContext & NextAppContext.
  // This allows us to consume the apolloClient inside our
  // custom `getInitialProps({ apolloClient })`.
  ctx.apolloClient = apolloClient;
  if (inAppContext) {
    ctx.ctx.apolloClient = apolloClient;
  }

  return ctx;
};

/**
 * Always creates a new apollo client on the server
 * Creates or reuses apollo client in the browser.
 * @param  {NormalizedCacheObject} initialState
 * @param  {NextPageContext} ctx
 */
const initApolloClient = (apolloClient: any, initialState: any, ctx: any) => {
  // Make sure to create a new client for every server-side request so that data
  // isn't shared between connections (which would be bad)
  if (typeof window === "undefined") {
    return createApolloClient(apolloClient(ctx), initialState, ctx);
  }

  // Reuse client on the client-side
  if (!globalApolloClient) {
    globalApolloClient = createApolloClient(
      apolloClient(ctx),
      initialState,
      ctx
    );
  }

  return globalApolloClient;
};

/**
 * Creates a withApollo HOC
 * that provides the apolloContext
 * to a next.js Page or AppTree.
 * @param  {Object} withApolloOptions
 * @param  {Boolean} [withApolloOptions.ssr=false]
 * @returns {(PageComponent: ReactNode) => ReactNode}
 */
export const createWithApollo = (ac: any) => {
  return ({ ssr = false } = {}) => (PageComponent: any) => {
    const WithApollo = ({ apolloClient, apolloState, ...pageProps }: any) => {
      let client;
      if (apolloClient) {
        // Happens on: getDataFromTree & next.js ssr
        client = apolloClient;
      } else {
        // Happens on: next.js csr
        client = initApolloClient(ac, apolloState, undefined);
      }

      return (
        <ApolloProvider client={client}>
          <PageComponent {...pageProps} />
        </ApolloProvider>
      );
    };

    // Set the correct displayName in development
    if (process.env.NODE_ENV !== "production") {
      const displayName =
        PageComponent.displayName || PageComponent.name || "Component";
      WithApollo.displayName = `withApollo(${displayName})`;
    }

    if (ssr || PageComponent.getInitialProps) {
      WithApollo.getInitialProps = async (ctx: any) => {
        const inAppContext = Boolean(ctx.ctx);
        const { apolloClient } = initOnContext(ac, ctx);

        // Run wrapped getInitialProps methods
        let pageProps = {};
        if (PageComponent.getInitialProps) {
          pageProps = await PageComponent.getInitialProps(ctx);
        } else if (inAppContext) {
          pageProps = await App.getInitialProps(ctx);
        }

        // Only on the server:
        if (typeof window === "undefined") {
          const { AppTree } = ctx;
          // When redirecting, the response is finished.
          // No point in continuing to render
          if (ctx.res && ctx.res.finished) {
            return pageProps;
          }

          // Only if dataFromTree is enabled
          if (ssr && AppTree) {
            try {
              // Import `@apollo/react-ssr` dynamically.
              // We don't want to have this in our client bundle.
              const { getDataFromTree } = await import(
                "@apollo/client/react/ssr"
              );

              // Since AppComponents and PageComponents have different context types
              // we need to modify their props a little.
              let props;
              if (inAppContext) {
                props = { ...pageProps, apolloClient };
              } else {
                props = { pageProps: { ...pageProps, apolloClient } };
              }

              // Take the Next.js AppTree, determine which queries are needed to render,
              // and fetch them. This method can be pretty slow since it renders
              // your entire AppTree once for every query. Check out apollo fragments
              // if you want to reduce the number of rerenders.
              // https://www.apollographql.com/docs/react/data/fragments/
              await getDataFromTree(<AppTree {...props} />);
            } catch (error) {
              // Prevent Apollo Client GraphQL errors from crashing SSR.
              // Handle them in components via the data.error prop:
              // https://www.apollographql.com/docs/react/api/react-apollo.html#graphql-query-data-error
              console.error("Error while running `getDataFromTree`", error);
            }

            // getDataFromTree does not call componentWillUnmount
            // head side effect therefore need to be cleared manually
            Head.rewind();
          }
        }

        return {
          ...pageProps,
          // Extract query data from the Apollo store
          apolloState: apolloClient.cache.extract(),
          // Provide the client for ssr. As soon as this payload
          // gets JSON.stringified it will remove itself.
          apolloClient: ctx.apolloClient,
        };
      };
    }

    return WithApollo;
  };
};

function createApolloClient(apolloClient: any, initialState: any, ctx: any) {
  // The `ctx` (NextPageContext) will only be present on the server.
  // use it to extract auth headers (ctx.req) or similar.
  apolloClient.ssrMode = Boolean(ctx);
  apolloClient.cache.restore(initialState);

  return apolloClient;
}
   import Router from "next/router";
    import { AppProps } from "next/app";

    
  
    
    function MyApp({ Component, pageProps }: AppProps) {
 
    
      return (
          <Component {...pageProps} /> 
      );
    }
    
    export default MyApp;
import React from "react";
import { withApollo } from "../apollo/withApollo";


const Index = () => <div></div>;

export default withApollo({ ssr: true })(Index);

这不是我想要的,@RomanHrybinchuk您的代码在服务器端和客户端都运行。如果您希望该查询只在服务器端运行,则必须使用getServerSideProps方法编写该查询。@RomanHrybinchuk是否修复了它?是的@SandroMennel,我可以在组件中附加您拥有的解决方案
useQuery
,您的期望是什么?如果希望请求发生在服务器上,我们需要将其移动到
getServerSideProps