I'm trying to use graphquery with react and gatsby but I can't get the data. I could get the data if it's written in js. How can I fix it? Thanks.
I started it from gatsby typesript starter but it doesn't work properly.
Uncaught ReferenceError: gatsby_1 is not defined
at ./src/templates/index-page.tsx.exports.IndexPageTemplate (index-page.tsx:56)
index.js:2177 The above error occurred in the <TemplateWrapper> component:
in TemplateWrapper (created by IndexPage)
React will try to recreate this component tree from scratch using the error boundary you provided, AppContainer.
I changed sitemetadata file from js to tsx and then the error happeend
SiteMetaData.tsx
import { graphql, useStaticQuery } from "gatsby";
const useSiteMetadata = () => {
const { data } = useStaticQuery(
graphql`
query GetSiteMetaData{
site {
siteMetadata {
title
description
}
}
}
`
);
return data.siteMetaData;
};
export default useSiteMetadata;
Layout.tsx
import * as React from "react";
import Helmet from "react-helmet";
import Footer from "../Organisms/Footer";
import Navbar from "../Organisms/Navbar";
import useSiteMetadata from "../Organisms/SiteMetadata";
interface TemplateWrapperProps {
children: React.ReactChild;
}
const TemplateWrapper: React.SFC<TemplateWrapperProps> = ({ children }) => {
const { title, description }: any = useSiteMetadata();
return (
<div>
<Helmet>
<html lang="ja" />
<title>{title}</title>
<meta name="description" content={description} />
<meta name="theme-color" content="#fff" />
<meta property="og:type" content="business.business" />
{/**<meta property="og:title" content={title} /> */}
<meta property="og:url" content="/" />
<meta property="og:image" content="/img/og-image.jpg" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
</Helmet>
<Navbar />
<div>{children}</div>
<Footer />
</div>
);
};
export default TemplateWrapper;
Try to separate graphql import into his own line, worked for me:
import { graphql } from 'gatsby';
import { Link, useStaticQuery } from 'gatsby';
There seem to be an issue open about it on gatsby-plugin-ts-loader repository: https://github.com/AdamLeBlanc/gatsby-plugin-ts-loader/issues/1#issuecomment-453876850
Related
import { getMeta } from '#/helpers/globalHelpers';
import Head from 'next/head';
import { useDispatch, useSelector } from 'react-redux';
import { increment, decrement, selectValue, bulkUpdate, reset } from '#/slicers/propertySlice';
import Link from 'next/link';
export default function Home({ meta }) {
const data = useSelector(selectValue);
const dispatch = useDispatch();
console.log(meta);
return (
<>
<Head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="og:title" content={meta.title} />
<meta name="og:description" content={meta.metadescription} />
<meta name="description" content={meta.metadescription} />
<meta name="keywords" content={meta.keywords} />
<title>{meta.title}</title>
</Head>
Hello world!
</>
)
}
export async function getServerSideProps({ resolvedUrl }) {
const pageData = await getMeta(resolvedUrl);
return {
props: { meta: pageData[0] }
}
}
I am working with next.js yarn and redux. I am trying to get my SEO data from my api and render is wit ssr. But it is rendering at the client side and SEO crawler tools (i am using screaming frog) can't see my title and description
Here is my code. I couldn't understand why my Head tag is rendering at the client side. Anyone can help?
Extra info, i checked _document.js, tag is correctly used and defined.
import { Html, Head, Main, NextScript } from 'next/document'
import Script from 'next/script'
export default function Document() {
return (
<Html>
<Head />
<body>
<Main />
<NextScript />
<Script src="assets/js/jquery.min.js"></Script>
<Script src="assets/bootstrap/js/bootstrap.min.js"></Script>
<Script src="assets/js/aos.min.js"></Script>
<Script src="assets/js/bs-init.js"></Script>
<Script src="assets/js/checkbox-show-hide.js"></Script>
<Script src="assets/js/dropdown-saver.js"></Script>
<Script src="assets/js/floatsearch.js"></Script>
<Script src="assets/js/heroclean.js"></Script>
<Script src="assets/js/location-list.js"></Script>
<Script src="assets/js/mobilemenu.js"></Script>
</body>
</Html>
)
}
A while ago I made a relatively massive app for a single developer for my own personal use - a "social media" of sorts. I wrote it in React.js
I have recently decided to revisit the app and revamp it - primarily make it server-side rendered using Next.js.
The key problem is loading the themes. I had a feature where I would programmatically add an external script tag to the end of the body which would manipulate the canvas and show some animations.
I had no issues when I worked with React, as everything got loaded the way I expected it to, but when it comes to Next, that simply isn't the case. The script tag loads, but the code doesn't get executed.
The most important files I have issues with are:
My _document.jsx file:
import Document, { Html, Head, Main, NextScript } from 'next/document'
import { BASE_URL as base } from '../config'
class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx)
return { ...initialProps }
}
render() {
return (
<Html lang={"en"}>
<Head>
<link rel={"icon"} href={`${base}/short.png`} />
<link
rel={"apple-touch-icon"}
href={`${base}/apple-icon-180x180-dunplab-manifest-34821.png`}
/>
<link
href="https://fonts.googleapis.com/css?family=Roboto&display=swap"
rel={"stylesheet"}
/>
<link
rel={"stylesheet"}
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.10.2/css/all.min.css"
integrity={"sha256-zmfNZmXoNWBMemUOo1XUGFfc0ihGGLYdgtJS3KCr/l0="}
crossOrigin={"anonymous"}
/>
<link
rel={"stylesheet"}
href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
integrity={"sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh"}
crossOrigin={"anonymous"}
/>
<script
defer
src={`${base}/Vector2.js`}
charSet={"utf-8"}
></script>
<link rel={"manifest"} href={`${base}/manifest.json`} />
</Head>
<body>
<div className="canvas-wrapper">
<canvas id="canvas" className="canvas-bg"></canvas>
<NextScript />
</div>
<Main>
<script
defer
src="https://code.jquery.com/jquery-3.4.1.slim.min.js"
integrity={"sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n"}
crossOrigin={"anonymous"}
></script>
<script
defer
src="https://cdn.jsdelivr.net/npm/popper.js#1.16.0/dist/umd/popper.min.js"
integrity={"sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"}
crossOrigin={"anonymous"}
></script>
<script
defer
src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"
integrity={"sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6"}
crossOrigin={"anonymous"}
></script>
</Main>
</body>
</Html>
)
}
}
export default MyDocument
My _app.jsx file:
import '../styles/globals.css'
import 'bootstrap/dist/css/bootstrap.min.css'
import { ThemeProvider } from "../contexts/ThemeContext";
import { FontProvider } from "../contexts/FontContext";
import { DevProvider } from "../contexts/DevContext";
import { LanguageProvider } from "../contexts/LanguageContext";
// import { SocketProvider } from "../contexts/SocketContext";
import { ColourProvider } from "../contexts/ColourContext";
import PageContent from '../components/layout/PageContent/PageContent';
import { useStore } from '../store';
import { useEffect } from "react"
import { Provider } from 'react-redux';
import Head from 'next/head';
import { BASE_URL as base } from '../config';
import Nav from "../components/layout/Nav/Nav"
import setAuthToken from '../utils/setAuthToken';
import { getUser } from '../actions/auth';
function MyApp({ Component, pageProps }) {
const store = useStore(pageProps.initialReduxState);
useEffect(() => {
if (localStorage.getItem('token')) {
setAuthToken(localStorage.getItem('token'))
}
store.dispatch(getUser())
})
return (
<>
<Head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta property="og:title" content="Impulse" />
<meta property="og:description" content="Make an impact. Change minds." />
<meta
property="og:image"
content={`${base}/favicon-96x96-dunplab-manifest-34821.png`}
/>
<meta
name="description"
content="Welcome to Impulse - make an impact, change minds. Impulse is dedicated to your enjoyment and pleasure!"
/>
<script defer src={`${base}/scripts/initlog.js`}></script>
<script defer src={`${base}/scripts/blurfocus.js`}></script>
<title>Impulse</title>
</Head>
<ColourProvider>
<DevProvider>
<FontProvider>
{/* <SocketProvider> */}
<ThemeProvider>
<LanguageProvider>
<Provider store={store}>
<PageContent>
<Nav />
<Component {...pageProps} />
</PageContent>
</Provider>
</LanguageProvider>
</ThemeProvider>
{/* </SocketProvider> */}
</FontProvider>
</DevProvider>
</ColourProvider>
</>
)
}
export default MyApp
My useScript.js hook
import { useRef } from "react"
import { BASE_URL as base } from "../config"
// actually, it's supposed to load a single script, not more of them
const useScripts = (script) => {
const scriptLoaded = useRef(false);
if (typeof window !== "undefined" && !scriptLoaded.current && script) {
const element = document.createElement("script");
element.src = `${base}/static/canvasThemes/${script}.js`;
element.type = "text/javascript";
const position = document.querySelector("head");
position.appendChild(element);
scriptLoaded.current = true;
}
};
export default useScripts
My PageContent.jsx file, which was previously referenced in the _app.jsx file:
import React, { useContext, useEffect, useState } from "react";
import { ThemeContext } from "../../../contexts/ThemeContext";
import { FontContext } from "../../../contexts/FontContext";
import { ColourContext } from "../../../contexts/ColourContext";
import StyledPageContent from '../../../styled/StyledPageContent';
import useScripts from "../../../hooks/useScript";
import cookie from 'cookie-cutter'
function PageContent(props) {
const { isDarkTheme, toggleTheme } = useContext(ThemeContext);
const { isLegacyFont } = useContext(FontContext);
const { colour } = useContext(ColourContext)
const [theme, setTheme] = useState("")
useEffect(() => {
const newOne = cookie.get("isDarkTheme")
console.log("NJUUAN _APP", newOne);
setTheme(() => newOne)
}, [])
useScripts(theme)
return (
<StyledPageContent
isDarkTheme={isDarkTheme}
isLegacyFont={isLegacyFont}
colour={colour}
>
{props.children}
</StyledPageContent>
);
}
export default PageContent;
I'm looking for a way to add a script programmatically and immediately execute it.
Important: ALL script tags I want to add are considered "themes", which would grab the canvas from the _document and manipulate its background colour/fill/add text etc.
I have been trying a million different things for a month now and am starting to lose hope.
Not sure if I'll get any help, but thanks in advance all the same!
I am trying to change the favicon dynamically on all browsers, I get a response from the backend containing an https link to the icon, I am using react-helmet to change the favicon but it only works on chrome and android and doesnt work on safari, any ideas? please check out the code below:
import React from "react";
import { Helmet } from "react-helmet";
import { FavIconProps } from "./FavIconProps.types";
export const FavIcon = (props: FavIconProps) => {
const { faviconLink } = props;
console.log(faviconLink);
return (
<Helmet>
<meta name="favicon" />
<meta data-react-helmet="true" content="yes" name="apple-mobile-web-app-capable" />
<meta
data-react-helmet="true"
name="apple-mobile-web-app-status-bar-style"
content="black-translucent"
/>
<link id="favicon" rel="icon" data-react-helmet="true" href={faviconLink} />
<link
rel="apple-touch-icon"
data-react-helmet="true"
sizes="180x180"
href={faviconLink} />
</Helmet>
);
};
export default FavIcon;
I added all the meta tags to create a twitter card but when I try to do the twitter validation it tells me: INFO: Page fetched successfully
INFO: 3 metatags were found
ERROR: No card found (Card error)
I don't think I can put all the meta tags in meta={[...]} because it doesn't work the same.
What can I do to resolve? It's important!!!
import React from 'react'
import PropTypes from 'prop-types'
import Helmet from 'react-helmet'
import Header from '../components/header'
import './index.css'
const Layout = ({ children, data }) => (
<div>
<Helmet
title={data.site.siteMetadata.title}
meta={[
{ name: 'description', content: data.site.siteMetadata.description },
{ name: 'keywords', content: data.site.siteMetadata.keywords },
]}
>
<meta name="twitter:card" content="summary" />
<meta
name="twitter:description"
content="xxx"
/>
<meta
name="twitter:title"
content="xxx"
/>
<meta property="og:locale" content="en_US" />
<meta property="og:type" content="website" />
<meta
property="og:title"
content="xxx"
/>
<meta
property="og:description"
content="xxx"
/>
<meta property="og:url" content="http://example.com/" />
<meta property="og:site_name" content="xxx" />
</Helmet>
<Header />
{children()}
</div>
)
Layout.propTypes = {
children: PropTypes.func,
}
export default Layout
export const query = graphql`
query SiteTitleQuery {
site {
siteMetadata {
title
description
keywords
}
}
}
`
INFO: Page fetched successfully
INFO: 3 metatags were found
ERROR: No card found (Card error)
I'm using Razzle for using React and Server Side Rendering with React Helmet. I have this problem when you use React Helmet to set meta tags with dynamic values, it's not displayed correctly. But it works if you set the meta tags with static values.
Please take a look at some codes.
SEO.js Component
import React, { Component } from 'react';
import { Helmet } from "react-helmet-async";
class SEO extends Component {
constructor(props) {
super(props);
this.state = {
title: this.props.title,
description: this.props.description,
image: this.props.image
}
}
shouldComponentUpdate(nextProps) {
if(this.props != nextProps) {
this.setState({
title: nextProps.title,
description: this.props.description,
image: nextProps.image
})
return true;
} else {
return false;
}
}
render() {
return (
<div>
<Helmet>
<title>{this.state.title ? this.state.title : "Volunteer Hub by Indorelawan"}</title>
<meta name="title" content={this.state.title ? this.state.title : "Volunteer Hub by Indorelawan"} />
<meta
name="description"
content={this.state.description ? this.state.description : "Volunteer Hub by Indorelawan adalah tempat kolaborasi antara relawan dan komunitas sosial yang memiliki semangat kerelawanan dan gotong royong untuk Indonesia."}
/>
<meta
property="og:title"
content={this.state.title ? this.state.title : "Volunteer Hub by Indorelawan"}
/>
<meta
property="og:description"
content={this.state.description ? this.state.description : "Volunteer Hub by Indorelawan adalah tempat kolaborasi antara relawan dan komunitas sosial yang memiliki semangat kerelawanan dan gotong royong untuk Indonesia."}
/>
<meta
property="og:image"
content={this.state.image ? this.state.image : "https://volunteerhub.id/assets/logo/seo.jpg"}
/>
<meta property="og:url" content="https://volunteerhub.id" />
<meta
name="twitter:title"
content={this.state.title ? this.state.title : "Volunteer Hub by Indorelawan"}
/>
<meta
name="twitter:description"
content={this.state.description ? this.state.description : "Volunteer Hub by Indorelawan adalah tempat kolaborasi antara relawan dan komunitas sosial yang memiliki semangat kerelawanan dan gotong royong untuk Indonesia."}
/>
<meta
name="twitter:image"
content={this.state.image ? this.state.image : "https://volunteerhub.id/assets/logo/seo.jpg"}
/>
<meta name="twitter:card" content="summary_large_image" />
</Helmet>
</div>
);
}
}
export default SEO;
Here is the example of setting up the static meta tags:
import React, {Component} from "react";
import SEO from "../../components/SEO";
class ScheduleContainer extends Component {
constructor(props) { super(props); }
render() {
return(
<div>
<SEO
title="Cek Jadwal | Volunteer Hub by Indorelawan"
description="Cek jadwal kegiatan di Volunteer Hub! Volunteer Hub by Indorelawan adalah tempat kolaborasi antara relawan dan komunitas sosial yang memiliki semangat kerelawanan dan gotong royong untuk Indonesia." />
</div>);
}
}
And here is the example of setting up the dynamic meta tags:
import React, {Component} from "react";
import axios from "axios";
import SEO from "../../components/SEO";
class EventContainer extends Component {
constructor(props) {
super(props);
this.state = {
event: {}
}
}
componentDidMount() {
axios.get('API_URL')
.then(response => {
this.setState({ event: response.data.result })
});
}
render() {
return(
<div>
<SEO
title={this.state.event.title}
description={this.state.event.description} />
</div>);
}
}
Server.js
import RootContainer from "./containers/RootContainer";
import React from "react";
import { StaticRouter } from "react-router-dom";
import express from "express";
import { renderToString } from "react-dom/server";
import { Helmet, HelmetProvider } from "react-helmet-async";
const assets = require(process.env.RAZZLE_ASSETS_MANIFEST);
const server = express();
server
.disable("x-powered-by")
.use(express.static(process.env.RAZZLE_PUBLIC_DIR))
.get("/*", (req, res) => {
const context = {};
const helmetContext = {};
const markup = renderToString(
<HelmetProvider context={helmetContext}>
<StaticRouter context={context} location={req.url}>
<RootContainer />
</StaticRouter>
</HelmetProvider>
);
const { helmet } = helmetContext;
if (context.url) {
res.redirect(context.url);
} else {
res.status(200).send(
`<!doctype html>
<html lang="">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<meta
name="keywords"
content="volunteer, hub, by, indorelawan, volunteer hub, volunteer hub by indorelawan, kolaborasi, dimulai, dari, sini, ubah, niat, baik, jadi, aksi, baik, hari, ini"
/>
<meta name="robots" content="index, follow" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="language" content="Indonesia" />
<meta name="author" content="Indorelawan" />
<meta name="msapplication-TileColor" content="#ffffff">
<meta name="theme-color" content="#222222" />
${helmet.title.toString()}
${helmet.meta.toString()}
${
assets.client.css
? `<link rel="stylesheet" href="${assets.client.css}">`
: ""
}
${
process.env.NODE_ENV === "production"
? `<script src="${assets.client.js}" defer></script>`
: `<script src="${
assets.client.js
}" defer crossorigin></script>`
}
...
</head>
<body>
<div id="root">${markup}</div>
<script>
if ("serviceWorker" in navigator) {
if (navigator.serviceWorker.controller) {
console.log("[PWA Builder] active service worker found, no need to register");
} else {
// Register the service worker
navigator.serviceWorker
.register("pwabuilder-sw.js", {
scope: "./"
})
.then(function (reg) {
console.log("[PWA Builder] Service worker has been registered for scope: " + reg.scope);
});
}
}
</script>
</body>
</html>`
);
}
});
export default server;
Now that you have seen the code, here is the result when I copy pasted to Google SERP Simulator and WhatsApp:
Static meta tags result from Schedule Page:
Google SERP Simulator
WhatsApp
Dynamic meta tags result from Event Page:
Google SERP Simulator
WhatsApp
From the result, it always return the default title and description tag not the title and description passed from the axios. Is is normal behavior or am I doing something wrong?
Razzle IS server side rendering, the problem with your dynamic meta tags scenario is that you're relying on data that is fetched in componentDidMount, and componentDidMount, as a lifecycle method from the commit phase, is not called on the server since there's no actual mounting on server side.
NextJS solves this problem for you because of getInitialProps, which is invoked on server and client.
Turns out Razzle is not Server Side Rendering. Either you have to define the SEO tags using a custom express server, or just use SSR for React.
I am using NextJS for this and this is a no problem.