How to add facebook Pixel on Next.js react app? - reactjs

I know this may be a dumb question.
How can I do to use facebook pixel on a next.js react app ?

there are no dumb questions.
You can see nextjs example about how implements fb pixel.
Nextjs Facebook Pixel

Solution with typescript and hook with NextJs
Install react-facebook-pixel yarn add react-facebook-pixel
In your file _app.tsx
// pages/_app.tsx
import { useEffect } from 'react'
import { useRouter } from 'next/router'
const App = ({ Component, pageProps }) => {
const router = useRouter()
useEffect(() => {
import('react-facebook-pixel')
.then((x) => x.default)
.then((ReactPixel) => {
ReactPixel.init('XXXXXXXXXXXXXXXXXXXXX') // facebookPixelId
ReactPixel.pageView()
router.events.on('routeChangeComplete', () => {
ReactPixel.pageView()
})
})
}, [router.events])
return <Component {...pageProps} />
}
export default App
Remark: it works with typescript or JavaScript

Use the new Script component released in Next.js version 11. Import the below into your _app.js.
import { useEffect } from 'react'
import { useRouter } from 'next/router'
import {pageview, FB_PIXEL_ID} from '../../lib/fpixel'
import Script from 'next/script'
const handleRouteChange = () => {
pageview()
}
const FB_PIXEL_ID = process.env.NEXT_PUBLIC_FACEBOOK_PIXEL_ID
const pageview = () => {
window.fbq('track', 'PageView')
}
const FacebookPixel = ({ children }) => {
const router = useRouter()
useEffect(() => {
// the below will only fire on route changes (not initial load - that is handled in the script below)
router.events.on('routeChangeComplete', handleRouteChange)
return () => {
router.events.off('routeChangeComplete', handleRouteChange)
}
}, [router.events])
return (
<Script id="facebook-pixel">
{`
!function(f,b,e,v,n,t,s)
{if(f.fbq)return;n=f.fbq=function(){n.callMethod?
n.callMethod.apply(n,arguments):n.queue.push(arguments)};
if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
n.queue=[];t=b.createElement(e);t.async=!0;
t.src=v;s=b.getElementsByTagName(e)[0];
s.parentNode.insertBefore(t,s)}(window, document,'script',
'https://connect.facebook.net/en_US/fbevents.js');
fbq('init', ${FB_PIXEL_ID});
fbq('track', 'PageView');
`}
</Script>
)
}
export default FacebookPixel
UPDATE
Do not use strategy="lazyOnload". I was previously using this and the script was more likely to be blocked by adblocker if using this method.

There's a library for React called react-facebook-pixel. In order to make it work with NextJs, try this solution in your _app.jsx file:
function FacebookPixel() {
React.useEffect(() => {
import("react-facebook-pixel")
.then((x) => x.default)
.then((ReactPixel) => {
ReactPixel.init('pixel ID here');
ReactPixel.pageView();
Router.events.on("routeChangeComplete", () => {
ReactPixel.pageView();
});
});
});
return null;
}
export default function App({ Component, pageProps }) {
return (
<>
<Head>
<meta charSet="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, viewport-fit=cover"
/>
</Head>
<FacebookPixel />
//…
<main className="routesContainer">
<Component siteData={siteData} {...pageProps} />
</main>
//…
</>
);
}
or in case you're using Class components, insert this in you componentDidMount() inside the App class:
componentDidMount() {
import('react-facebook-pixel')
.then((x) => x.default)
.then((ReactPixel) => {
ReactPixel.init('Pixel ID Here');
ReactPixel.pageView();
Router.events.on('routeChangeComplete', () => {
ReactPixel.pageView();
});
});
}
font: https://github.com/zsajjad/react-facebook-pixel/issues/53

Simple and easy:
Put the below code inside _app.js:
useEffect(async () => {
const { default: ReactPixel } = await import('react-facebook-pixel');
ReactPixel.init(FB_PIXEL, null, {
autoConfig: true,
debug: true,
});
ReactPixel.pageView();
ReactPixel.track("ViewContent")
});

Related

Can I change page title in reactjs in this way (using useState and useEffect)?

I don't know why it's not working. Does it have any syntax error tho?
const [pageTitle, setPageTitle] = useState("My Financial Right Hand");
useEffect(() => {
document.title = pageTitle;
}, [pageTitle]);
function changePageTitle(props) {
setPageTitle(props);
};
and inside render:
{changePageTitle("Main Page")}
You should use react-helmet which runs as a side effect to change the title, metadata ...etc.
import React, { useEffect, useState } from "react";
import { Helmet } from "react-helmet";
export default function App() {
const [pageTitle, setPageTitle] = useState("My Financial Right Hand");
return (
<>
<Helmet>
<title>{pageTitle}</title>
</Helmet>
<p>tsample text</p>
</>
);
}
Try implementing a custom hook
export function useTitle(title) {
useEffect(() => {
const prevTitle = document.title
document.title = title
return () => {
document.title = prevTitle
}
})
}
call the function as below
const MyComponent = () => {
useTitle("New Title")
return (
<div>
...
</div>
)
}

Mocking next/head does not seem to do anything

I have a Seo component that uses the next/head component. I would like to test this Seo component, but mocking next/head seems to do nothing at all. Am I doing something wrong?
import TestRenderer from 'react-test-renderer';
import Seo from '../Seo';
jest.mock(
"next/head",
() => function Head({ children }) {
return children;
},
);
it('should display seo', () => {
const render = TestRenderer.create(
<Seo />,
);
expect(render.toJSON()).toMatchSnapshot();
});
import Head from "next/head";
function Seo() {
return (
<Head>
<title>Title SEO</title>
</Head>
);
}
This works for me (remove typescript if just using js)
jest.mock('next/head', () => {
return {
__esModule: true,
default: ({ children }: { children: Array<React.ReactElement> }) => {
return <>{children}</>;
},
};
});
I'm not sure if the test should be delayed to wait for the DOM manipulation to end. Also document.head might be needed to be provided as a container.
it('should display seo', async () => {
const render = TestRenderer.create(
<Seo />, {container: document.head}
);
await waitFor(() => {
expect(render.toJSON()).toMatchSnapshot();
});
});

React-router-dom does not scroll to top of page

I'm going crazy, I'm using react-router-dom, the moment I go from page A to B I want it to start at the top of the page, everywhere. I've tried different things like:
componentDidUpdate(){
console.log('hello');
document.documentElement.scrollTo(0, 0)
}
&
componentDidUpdate(){
console.log('hello');
window.scrollTo(0, 0)
}
&
import { useEffect } from 'react';
import { withRouter } from 'react-router-dom';
function ScrollToTop({ history }) {
useEffect(() => {
const unlisten = history.listen(() => {
window.scrollTo(0, 0);
});
return() => {
unlist();
}
}, []);
return(null);
}
export default withRouter(ScrollToTop);
But unfortunately without success, is there anyone who can tell me what I can do? I'm using :react": "^16.14.0"
So the intention is if I click on a <Link to={'../shopping cart'}>Shopping cart</Link> I will end up at the top of the page!
maybe you can use useRef hook. something like this:
const linkRef = useRef(null);
useEffect(() => {
if (linkRef.current) {
linkRef.current.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
}, []);
return <Link ref={linkRef} to='/shopping-card' />

Router Events and preloader without state in NextJS

I am trying to convert this code to not use state as I have heard using setState in _app.js is not recommended and leads to errors. I can't quite figure out how to do it. Any help would be awesome.
Thanks
export default class BookingApp extends App {
.....
componentDidMount() {
Router.events.on('routeChangeStart', () => {
this.setState({ isLoading: true })
})
Router.events.on('routeChangeComplete', () => {
this.setState({ isLoading: false })
})
Router.events.on('routeChangeError', () => {
this.setState({ isLoading: false })
})
}
return (
....
{this.state.isLoading && (
<div>
<Loader />
</div>
)}
...Other Content
Currently you have only made the UI aspect of the Loader into a separate component.
Move the entire logic into the seperate Loader component instead of the _app.js file.
Below is a hooks implementation of the Loader component. It can be done using class components too.
import { useEffect, useState } from 'react';
import { useRouter } from 'next/router';
const Loader = () => {
const router = useRouter();
const [isLoading, setIsLoading] = useState(false);
useEffect(() => {
router.events.on('routeChangeStart', () => {
setIsLoading(true);
});
router.events.on('routeChangeComplete', () => {
setIsLoading(false);
});
router.events.on('routeChangeError', () => {
setIsLoading(false);
});
}, []);
return (
<>
{
isLoading && (
<LoaderUIComponentComesHere />
)
}
</>
);
};
export default Loader;

React hooks - remove from react-router location state when we refresh page

When I am entering one page of the app I pass data through location state using react-router. Then I access it via location.state.myDataObject. When I refresh the page it is still there, while I would like it to be empty. Here's what I've try to use:
const resetLocation = () => {
history.replace({
...location,
state: undefined,
});
};
useEffect(() => {
window.addEventListener('onbeforeunload', resetLocation);
}, []);
Or adding it to unmount action within useEffect but I guess it is not called when refreshing the page:
useEffect(() => {
return function cleanLocationState() {
history.replace({
...this.props.location,
state: undefined,
});
};
}, []);
I think this is the desired behavior of react router. If you want to reset the state then you need to do something like
import React, { useEffect, useCallback } from "react";
import { useLocation, useHistory } from "react-router-dom";
function Home() {
const location = useLocation();
const history = useHistory();
const replaceHistory = useCallback(() => {
history.replace({ ...location, state: undefined });
}, [history]);
useEffect(() => {
window.addEventListener("beforeunload", () => replaceHistory);
return () => {
window.removeEventListener("beforeunload", replaceHistory);
};
}, []);
return (
<div>
<h2>Home</h2>
</div>
);
}
export default Home;
Working example
How about you try the contrary? Store the value on component did mound and delete it from the location. I'm not sure that this is the prettiest solution, but i guess it's the easiest
const [state,setState]=useState();
useEffect(()=>{
setState(location.state);
location.state=undefined;
}, [location])
Try this way:
import React, { useEffect } from "react";
import { useHistory } from "react-router-dom";
function Home() {
const history = useHistory();
function replaceHistory(e) {
if (e) {
e.preventDefault();
delete e.returnValue;
}
history.replace({ ...history.location, state: undefined });
}
console.log("history", history.location);
useEffect(() => {
window.addEventListener("beforeunload", () => replaceHistory);
return () => {
// Reset Location state if we leave this page
replaceHistory();
window.removeEventListener("beforeunload", replaceHistory);
};
}, []);
return (
<div>
<h2>Home</h2>
</div>
);
}
export default Home;
CodesandBox Demo
The default behavior of the react-router will not save the history state after refresh the page so we need to know more about your code to really solve this issue. However, if the state do save, byour first attempt seem to have some flaw by using the history and location of window instead from the props.
function Page(props){
useEffect(() => {
const unloadFunc = () => {
//use the history and the location from the props instead of window
props.history.replace({
...props.location,
state: undefined,
});
}
window.addEventListener('onbeforeunload',unloadFunc);
return ()=>{
window.removeEventListener('onbeforeunload' unloadFunc);
//make history and location as the dependencies of the hook
}, [props.history, props.location]);
return <div></div>
}

Resources