react-seo
v1.0.11
Published
Make your Ajax powered Reactjs pages visibile to Google
Downloads
33
Readme
If you've ever worked on a React.js web application, and then tried to do SEO for the website and submit some of your pages to Fetch as Google, you might have discovered that instead of seeing your page content, Google only sees a blank page:
If you've tried a find a solution for that problem, you probably seen online that you'll going to need to switch to server side rendering, which can be pretty time consuming and complex to convert your client side rendered app to server side rendering (not to mention having to install NodeJS on your server).
The thing about Google's crawlers is that although they do execute Javascript, they will not wait for an AJAX call to return if the AJAX call was made after the page render. What I discovered however, is that the crawlers will wait for an AJAX call to be returned if the call was made before the page render.
react-seo allows you to do exactly that via a configurable API.
And the result? :
npm install --save react-seo
Import the package in your index.js file
import ReactSEO from 'react-seo';
Then call
ReactSEO.startMagic(urls,renderDOMFunction)
Urls is a list of objects, that each object represents a url to enable Google indexing on. Each object sould have those properties:
renderDOMFunction is a function the will call your ReactDOM.render function.
Other functions:
index.js:
import React from 'react';
import Page1 from '../components/Page1.js';
import Page2 from '../components/Page2.js';
import ReactDOM from 'react-dom';
import ReactSEO from 'react-seo';
ReactSEO.startMagic([{url:'/products/',isFullMatch:false,
ajaxFunction:fetchGameData,urlParams:[/(.+\/products\/|\/[^\/]+)/g]}],renderDOM);
function renderDOM(){
ReactDOM.render(
<BrowserRouter basename='/' >
<div>
<Route path = '/' component={Page1} />
<Route path='/products/:id' component={Page2} />
</div>
</BrowserRouter>
,app);
}
Page2.js:
import React from 'react';
import axios from 'axios';
import CustomLoader from './CustomLoader';
import AppBar from './AppBar';
import GameDataStore from './GameDataStore';
import { fetchGameData } from './actions';
import Footer from './Footer';
export default class Page2 extends React.Component{
constructor(){
super();
this.state={loading:true,GameData: GameDataStore.getGameData()};
}
componentWillMount(){
GameDataStore.on('gameDataIsInDaHouse',this.setData);
// Checks if data was already fetched
if (this.props.match.params && this.state.GameData.id !== this.props.match.params.id) // is data missing?
{
fetchGameData(this.props.match.params.id);
}
else{ // data was already fetched, no need to fetch again.
this.setState({loading:false})
}
}
componentWillUnmount(){
GameDataStore.removeListener('gameDataIsInDaHouse',this.setData);
}
setData(){
const GameData = GameDataStore.getGameData();
this.setState({GameData,loading:false});
}
render(){
const data = (<div>
<h2>{this.state.GameData.title}</h2>
<h5>{this.state.GameData.price}</h5>
</div>);
return (
<div>
<AppBar />
{this.state.loading ? <CustomLoader /> : data}
<Footer />
</div>
);
}
ajaxFunction's ajax request:
function ajaxFunction(param,resolve){
axios.get(`/api?param=${param}`)
.then((response)=>{
// do stuff
this.emit('gameDataIsInDaHouse');
if (resolve) // IMPORTANT! call resolve only if it was passed.
resolve();
});
}