I'm using ReactJS server side rendering with express and react-apollo.
Everything working perfectly until I use WP acf PRO.
GraphiQL show these fields, also if I console.log it in reactjs component it shows these values in node server only not in client side. But If I remove ACF pro fields then react-apollo get everything in cient side also.
Query I use:
const TEST_DATA = gql`
query test {
page(id: "/homepage", idType: URI, asPreview: false) {
homePageCustom {
homePage {
__typename
... on Page_Homepagecustom_HomePage_SomeData {
enabled
fieldGroupName
}
}
}
}
}
`;
Component I use:
const FrontPage = (props) => {
const { loading, error, data } = useQuery(TEST_DATA, {
fetchPolicy: 'cache-and-network',
errorPolicy: "all",
variables: {},
onError: (d) => {
console.log(d);
},
onCompleted: (d) => {
console.log("onComplete", d);
},
});
if (loading) return <div>...Loading</div>;
if (error) return `Error! ${error.message}`;
console.log("data", data, error, loading);
return (
<div>
Some data here
</div>
);
};
export default FrontPage;
If I use that query then client side show data and working:
const TEST_DATA = gql`
query test {
page(id: "/homepage", idType: URI, asPreview: false) {
homePageCustom {
homePage {
__typename
... on Page_Homepagecustom_HomePage_SomeData {
__typename
}
}
}
}
}
`;
My client side settings:
const cache = new InMemoryCache();
const client = new ApolloClient({
link: createHttpLink({ uri: webConfig.siteURLGraphQL }),
cache: cache.restore(window.__APOLLO_STATE__),
});
const SSRApp = (
<ApolloProvider client={client}>
<BrowserRouter>
<CookiesProvider>
<App />
</CookiesProvider>
</BrowserRouter>
</ApolloProvider>
);
ReactDOM.hydrate(SSRApp, document.querySelector("#root"));
Its interesting that window._ APOLLO_STATE _ get these values I need.
Maybe there are some settings error in my react-apollo setup?
Im really confused and tried 3 days and nothing seems working.
Related
I want to build my next js project in which i am using
https://www.npmjs.com/package/#react-oauth/google
but when I build it i get the following :
this is layout.js and in _app.js I have all the components wrapped in GoogleOAuthProvider
import { GoogleLogin } from '#react-oauth/google';
import {FcGoogle} from "react-icons/Fc"
import { useGoogleLogin } from '#react-oauth/google';
export default function Layout({ children }) {
const client_id = ""
const responseGoogle = (response) => {
console.log(response);
}
CUTTED (NOT RELEVANT)
const login = useGoogleLogin({
onSuccess: codeResponse => {
const { code } = codeResponse;
console.log(codeResponse)
axios.post("http://localhost:8080/api/create-tokens", { code }).then(response => {
const { res, tokens } = response.data;
const refresh_token = tokens["refresh_token"];
const db = getFirestore(app)
updateDoc(doc(db, 'links', handle), {
refresh_token : refresh_token
})
updateDoc(doc(db, 'users', useruid), {
refresh_token : refresh_token
}).then(
CUTTED (NOT RELEVANT)
)
}).catch(err => {
console.log(err.message);
})
},
onError: errorResponse => console.log(errorResponse),
flow: "auth-code",
scope: "https://www.googleapis.com/auth/calendar"
});
return (
<>
CUTTED (NOT RELEVANT)
</>
)
}
Everything works perfect in dev mode but it does not want to build
I've faced this issue too. So I use 'GoogleLogin' instead of 'useGoogleLogin', then you can custom POST method on 'onSuccess' property.
import { GoogleLogin, GoogleOAuthenProvider} from '#react-oauth/google';
return(
<GoogleOAuthProvider clientId="YOUR CLIENT ID">
<GoogleLogin
onSuccess={handleLogin}
/>
</GoogleOAuthProvider>
The async function will be like...
const handleLogin = async = (credentialResponse) => {
var obj = jwt_decode(credentialResponse.credential);
var data = JSON.stringify(obj);
console.log(data);
const data = {your data to send to server};
const config = {
method: 'POST',
url: 'your backend server or endpoint',
headers: {},
data: data
}
await axios(config)
}
Spending whole day, this solve me out. Just want to share.
You have to wrap your application within GoogleOAuthProvider component. Please keep in mind that you will need your client ID for this.
import { GoogleOAuthProvider } from '#react-oauth/google';
<GoogleOAuthProvider clientId="<your_client_id>">
<SomeComponent />
...
<GoogleLoginButton onClick={handleGoogleLogin}/>
</GoogleOAuthProvider>;
I am serving my next.js on Vercel (I tried Amplify as well). Page works but components that require data from getServerSideProps() in my pages/index.tsx are not required. It seems that function isn't called at all.
Could anyone help me fix this issue?
export default function Home({ cryptosData, tempObject }) {
return (
<>
{tempObject && <Converter tempObject={tempObject} />}
{cryptosData && <MainTable data={cryptosData} />}
</>
);
}
export const getServerSideProps = async () => {
const url =
"https://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest";
const query = "?limit=80";
try {
const res = await fetch(url + query, {
headers: { "X-CMC_PRO_API_KEY": process.env.API_KEY },
});
const json = await res.json();
const data = json.data;
const [cryptosData, tempObject] = parseData(data, 40);
return {
props: { cryptosData, tempObject },
};
} catch (error) {
console.log(error);
return {
props: {},
};
}
};
I had the same issue. And the reason was in headers I sent with API requests
This is my apollo client code.
import {
ApolloClient,
ApolloLink,
createHttpLink,
InMemoryCache
} from "#apollo/client"
import { setContext } from "#apollo/client/link/context"
let uri = `${process.env.NEXT_PUBLIC_API_URL}/wp/graphql`
const httpLink = createHttpLink({ uri, credentials: "include" })
const authLink = setContext((_, { headers }) => {
headers
})
let client = new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache(),
defaultOptions: {
query: {
fetchPolicy: "no-cache"
}
}
})
export { client }
This is my page routing in next where i am trying a simple GraphQL Query.
export default function PrivatePath(props: any) {
console.log("props:", props)
const { data, loading, error } = useQuery(gql`
query MyQuery {
page(id: "/min-sida", idType: URI) {
status
title
}
}
`)
console.log("data:", data)
return (
<ApolloProvider client={client}>
<AuthProvider>
<div></div>
</AuthProvider>
</ApolloProvider>
)
}
export async function getServerSideProps(context: any) {
const slugs = context.query.path[0]
const query = gql`
query MyQuery {
page(id: "/min-sida", idType: URI) {
status
title
}
}
`
const data = await client.query({ query: query })
return {
props: data
}
}
What is interesting to me is that the hook useQuery, does what is expected and when logged in delivers the page title and status.
The client.query, however, does not ever return page title and status, even when logged in it simple returns page: { null }.
My initial thought was that it was because getStatiProps in next won't be able to get the data no matter what, but it seems getServerSideProps is unable to do so as well?
Does anyone have a decent idea for solving this?
I have created subscription whenever a new post is added. The subscription works fine on the graphiql interface.
Here is my react code to use useSubscription hook
export const SUSCRIBE_POSTS = gql`
{
subscription
posts {
newPost {
body
id
createdAt
}
}
}
`;
const {
loading: suscriptionLoading,
error: subscriptionError,
data: subscriptionData,
} = useSubscription(SUSCRIBE_POSTS);
when I try to console log subscriptionData I get nothing. when I add a post it is saved in database correctly, the useQuery hook for getting posts also work fine, but when I add a new post I don't see the subscription data. I can't see anything wrong in the console as well. When I log suscriptionLoading, Ido get true at the start. I am not sure how to debug this.
The client setup is done correctly according to the docs https://www.apollographql.com/docs/react/data/subscriptions/
and here is the code
const httpLink = createHttpLink({
uri: "http://localhost:4000/",
});
const wsLink = new WebSocketLink({
uri: `ws://localhost:4000/graphql`,
options: {
reconnect: true,
},
});
const authLink = setContext(() => {
const token = localStorage.getItem("jwtToken");
return {
headers: {
Authorization: token ? `Bearer ${token}` : "",
},
};
});
const link = split(
// split based on operation type
({ query }) => {
const definition = getMainDefinition(query);
return (
definition.kind === "OperationDefinition" &&
definition.operation === "subscription"
);
},
wsLink,
authLink.concat(httpLink)
);
const client = new ApolloClient({
link: link,
cache: new InMemoryCache(),
});
export default (
<ApolloProvider client={client}>
<App />
</ApolloProvider>
);
export const SUSCRIBE_POSTS = gql`
subscription
posts {
newPost {
body
id
createdAt
}
}
`;
Can you try to remove the most-outside brackets of subscription gql?
I'm trying to make my React components tree aware of any network errors that happen in my app. These errors are actually being catched like this:
const errorLink = onError(({ graphQLErrors, networkError, operation }) => {
const { cache } = operation.getContext();
if (graphQLErrors) {
graphQLErrors.map(({ message }) => console.log(`GraphQL Error: ${message}`));
cache.writeData({ data: { error: { message: graphQLErrors[0].message } } });
}
if (networkError) {
console.log(`Network Error: ${networkError.message}`);
cache.writeData({ data: { error: { statusCode: networkError.statusCode } } });
}
});
const httpLink = new HttpLink({
credentials: 'include',
uri: config.apiGraphql,
});
const client = new ApolloClient({
cache,
link: from([
errorLink,
httpLink,
]),
typeDefs,
resolvers,
});
My onError triggers on every graphql request and if there is any error, my actual approach is to write it to my Apollo local cache.
The problem is, I have no idea how to make a component that is being rendered somewhere in the middle of my tree aware of this.
I have a query to read this value, but it doesn't rerender when I write to cache.
The component is like this:
import React, { Fragment } from 'react';
import { useQuery } from '#apollo/react-hooks';
import PropTypes from 'prop-types';
import { GET_ERROR } from 'graph/query/Commons/common';
const ErrorHandler = ({ children }) => {
const { data } = useQuery(GET_ERROR);
console.log(data && data.error);
return data && data.error
? (
<Fragment>
AN ERROR HAPPENED
{data && data.error}
</Fragment>
)
: children;
};
ErrorHandler.propTypes = { children: PropTypes.any };
export default ErrorHandler;
Of course, when it first renders, there is no error at all. Then I write to cache, but ErrorHandler never realizes this.
I have tried using writeQuery without success... maybe because I'm lacking a _id or __typename field?
Is there any other way to pass this error to my components?
My React version is 16.8.
In the end, writeQuery was the way to go.
After some trial/error I reached this code for my errorLink which works perfectly:
const errorLink = onError(({ graphQLErrors, networkError, operation }) => {
const { cache } = operation.getContext();
if (graphQLErrors) {
graphQLErrors.map(({ message }) => console.log(`GraphQL Error: ${message}`));
}
if (networkError) {
console.log(`Network Error: ${networkError.message}`);
}
if (graphQLErrors || networkError) {
cache.writeQuery({
query: GET_ERROR,
data: {
error: {
__typename: 'error',
message: graphQLErrors[0].message,
statusCode: networkError.statusCode,
},
},
});
}
});
All I had to do was to make Apollo aware of the change happening to the GET_ERROR query. That query is the same one my ErrorHandler component is using.
I fixed my issues by setting errorPolicy: 'none' then you can catch graphQLErrors object from your component.
yourQuery(){
return apolloClient.query({
// your code
errorPolicy: 'none'
}).catch(({ graphQLErrors }) => {
// handle here
});
}