React diagram invisible and shows error at <DefaultLinkModel> - reactjs

I tried using react-diagrams library and I'm facing some problems.
Firstly at the line
const link = port1.link<DefaultLinkModel>(port2);
it shows me a error that
TypeError: link.addLabel is not a function
and suppose I remove the linking part, the code runs, I get no errors but nothing is seen on the webpage...
here is the code
App.js
import React from "react";
import createEngine, {
DefaultLinkModel,
DefaultNodeModel,
DiagramModel
} from "#projectstorm/react-diagrams";
import { CanvasWidget } from "#projectstorm/react-canvas-core";
// create an instance of the engine with all the defaults
const engine = createEngine();
// node 1
const node1 = new DefaultNodeModel({
name: "Node 1",
color: "rgb(0,192,255)"
});
node1.setPosition(100, 100);
let port1 = node1.addOutPort("Out");
// node 2
const node2 = new DefaultNodeModel({
name: "Node 1",
color: "rgb(0,192,255)"
});
node2.setPosition(100, 100);
let port2 = node2.addOutPort("Out");
// link them and add a label to the link
const link = port1.link < DefaultLinkModel > port2;
link.addLabel("Hello World!");
const model = new DiagramModel();
model.addAll(node1, node2);
engine.setModel(model);
class App extends React.Component {
render() {
return <CanvasWidget engine={engine} />;
}
}
export default App;
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from "./App"
import * as serviceWorker from './serviceWorker';
ReactDOM.render(<App />, document.getElementById('root'));
serviceWorker.unregister();
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<title>React App</title>
</head>
<body>
<style>
.srd-diagram {
height: 100vh;
}
</style>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
pls, help me sort this...

I know this post is too old, but still can be helpful if someone is struggling.
If you want to add the link between the nodes, try setting the source and target port for the link.
const node1 = new DefaultNodeModel({
name: "Node 1",
color: "rgb(0,192,255)",
});
node1.setPosition(100, 100);
let port1 = node1.addOutPort("Out");
const node2 = new DefaultNodeModel({
name: "Node 2",
color: "rgb(0,100,255)",
});
node2.setPosition(100, 200);
let port2 = node2.addInPort("In");
const link = new DefaultLinkModel();
link.setSourcePort(port1);
link.setTargetPort(port2);
For the second part:
and suppose I remove the linking part, the code runs, I get no errors but nothing is seen on the webpage...
You need to set the canvas height and width to make it visible.
App.js
<CanvasWidget className="canvas" engine={engine} />
App.css
.canvas {
height: 400px;
width: 100%;
}

Related

To publish Unity default AR Project with React Unity WebGL has a different serialization error

Development Environment
Macbook M1 Pro (With Apple Silicon Chip)
Unity 2021.3.10f1 (Be compatible with Apple Silicon Chip)
Test with Chrome Browser
Current Progress
I just create a new project with AR template
The project's hierarchy is like below picture.
That building Setting is like below picture.
After building, I get 4 files named build.data, build.framework.js, build.loader.js, build.wasm
With a create-react-app command, I created a new react project. (npx create-react-app ar_tutorial_4 --template typescript)
I located those 4 build files under the react's build directory. Like below image.
I edited index.html file like this.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>React Unity webGL</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
And, I edited App.tsx file and index.tsx file like this.
// App.tsx
import { useRef } from "react";
import { Unity, useUnityContext } from "react-unity-webgl";
function UnityTest() {
const {
unityProvider,
isLoaded,
loadingProgression,
} = useUnityContext({
codeUrl: '/build/build.wasm',
dataUrl: '/build/build.data',
frameworkUrl: '/build/build.framework.js',
loaderUrl: '/build/build.loader.js',
webglContextAttributes: {
preserveDrawingBuffer: true,
},
});
const loadingPercentage = Math.round(loadingProgression * 100);
const canvasRef = useRef<HTMLCanvasElement>(null);
return (
<div className="container">
{isLoaded === false && (
<div className="loading-overlay">
<p>Loading... ({loadingPercentage}%)</p>
</div>
)}
<Unity
className="unity"
unityProvider={unityProvider}
style={{ border: "1px solid red", height: 400, width: 500 }}
devicePixelRatio={window.devicePixelRatio}
ref={canvasRef}
/>
</div>
);
}
export { UnityTest };
// index.tsx
import React, { createElement } from 'react';
import ReactDOM from 'react-dom/client';
import { UnityTest } from './App';
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(createElement(UnityTest));
Problem
The screen was normally disappeared but the unity container did not played well.
And, this console error message was displayed.
build.framework.js:1771 A scripted object (script unknown or not yet loaded) has a different serialization layout when loading. (Read 52 bytes but expected 76 bytes)
Did you #ifdef UNITY_EDITOR a section of your serialized properties in any of your scripts?
Question
What should I do to resolve this problem??

React Component not working properly with Mapbox

I'm new on React, but due to requirements at an assigment in college, I must use it . I must do a single page application (SPA), with various components. I used npx create-react-app to setup the base project, and so you have an idea, it looks like this right now:
Each functionality such as "create new node", "create new line", etc, is an individual component.
On my App.js, I'm setting a state for each component as false, only making it true when the key of the submenu associated with that specific component is clicked, allowing me to switch between the sidebar options with no problem, and then at each component, I have display: false at the state and also this:
componentWillUpdate(nextprops) {
if (nextprops.display !== this.props.display) {
this.setState({ display: nextprops.display });
}
}
so it makes that display true, so that component is loaded. Everything works nicely, only the map viewer has a problem where the map by mapboxgl displays in full screen, covering the sidebar, not allowing me to change between components. The MapViewer component code is:
import React, { Component } from "react";
import mapboxgl from "mapbox-gl";
//import 'mapbox-gl/dist/mapbox-gl.css'
mapboxgl.accessToken="MY_KEY_IS_HERE";
class MapViewerComp extends Component {
constructor(props) {
super(props);
this.state = {
longitude: -8.562298,
latitude: 41.187181,
zoom: 12,
display: false,
};
}
componentWillUpdate(nextprops) {
if (nextprops.display !== this.props.display) {
this.setState({ display: nextprops.display });
}
}
displayTheMap = () => {
const map = new mapboxgl.Map({
container: "root",
style: "mapbox://styles/mapbox/streets-v11",
center: [this.state.longitude, this.state.latitude],
zoom: this.state.zoom
});
var marker = new mapboxgl.Marker().setLngLat([-8.562298, 41.187181]).addTo(map);
};
render() {
let pageContent = <div></div>;
if (this.state.display) {
pageContent = (
<div>
<div ref={this.displayTheMap} className="mapContainer"/>
</div>
);
}
return <div>{pageContent}</div>;
}
}
export default MapViewerComp;
And the .css looks like this:
.ant-switch-handle {
text-align: right;
}
.mapContainer {
position: absolute;
top: 0;
right: 0;
left: 0;
bottom: 0;
}
When I click the "Map Viewer" option on my sidebar (which corresponds to my (MapViewerComp), it pops out like this:
Since I'm new to React and frontend, the only was I was able to force it to fit my screen like this:
was to add this piece to the .css of this component:
.mapboxgl-canvas{
position: absolute;
left: 271px;
top: 65px;
}
The 2 problems are:
1st: if I force it to the size I want like I showed you, now when I zoom in and out on the map, the marker moves around and doesn't stay in place.
2nd: when I click the other options on the sidebar, to switch between functionalities, it doesn't work, it keeps showing the map.
The code of the index.js at src(with the npx create-react-app structure) is:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './components/app/App';
import reportWebVitals from './reportWebVitals';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
reportWebVitals();
And the code for the index.html on public folder is:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<link rel="icon" href="%PUBLIC_URL%/favicon.ico"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<meta name="theme-color" content="#000000"/>
<meta name="description" content="Web site created using create-react-app"/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png"/>
<link rel="manifest" href="%PUBLIC_URL%/manifest.json"/>
<script src="../src/components/mapViewerComp/MapViewerComp.js"></script>
<link href='https://api.mapbox.com/mapbox-gl-js/v1.13.0/mapbox-gl.css' rel='stylesheet' />
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
here's the structure of the project as well if it helps in any way:
Any fix to any of the issues would be appreciated. All other components work like a charm, yet the map viewer is not...
Thank you in advance.
Edit: Turns out the mapbox is set to render inside of the app root container, which why it is taking all the available space and not going away when re-rendering the app. Setting margins exposes the sidebar and allows to interact with it but alas doesn't trigger the map to go away.
See the doc here.

Botframework with Reactjs is not working on IE11

botframework with react is not working in IE,
I'm using my index html file similar to
https://github.com/microsoft/BotFramework-WebChat/tree/master/samples/03.a.host-with-react, its working in chrome but not in IE, i tried using webchat-es5.js also.
I'm using token given by bot team.
<!DOCTYPE html>
<html lang="en-US">
<head>
<title>Web Chat: Integrate with React</title>
<script src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>
<script src="https://unpkg.com/react#16.5.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16.5.0/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/react-redux#5.0.7/dist/react-redux.min.js"></script>
<script src="https://cdn.botframework.com/botframework-webchat/latest/webchat-es5.js"></script>
<style>
html, body { height: 100% }
body { margin: 0 }
#webchat {
height: 100%;
width: 100%;
}
</style>
</head>
<div id="webchat" role="main"></div>
<script type="text/babel">
function start() {
const { createStore, ReactWebChat } = window.WebChat;
const { Provider } = window.ReactRedux;
const store = createStore();
window.ReactDOM.render(
<Provider store={ store }>
<ReactWebChat
directLine={ window.WebChat.createDirectLine({ token:'mytoken' }) }
storeKey="webchat"
/>
</Provider>,
document.getElementById('webchat')
);
document.querySelector('#webchat > *').focus();
}
start();
</script>
</body>
</html>
working in Chrome but not in IE, somebody help me on this please.
Unfortunatley, the "webchat-es5.js" package was designed for instantiating web chat via the window.WebChat.renderWebChat method. While the "webchat.js" package does allow for using window.ReactDOM.render, it is not designed for older browsers, such as IE.
I played with this a bunch and was simply unable to render web chat using window.ReactDOM.render while also in IE, despite utilizing any number of polyfills. That being said, I was able to get the hosted React web chat sample to work in a proper React project with a few of modifications. Please note, this also makes use of webpack.
Hope of help!
index.js: Nothing special or unexpected here.
import React from 'react';
import ReactDOM from 'react-dom';
import App from './app';
import './css/index.css';
import * as serviceWorker from './serviceWorker';
ReactDOM.render(<App />, document.getElementById('root'));
serviceWorker.unregister();
app.js: Just some necessary routing.
import React, { Component } from 'react';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import WebChatView from './webChatView';
class App extends Component {
render() {
return (
<Router>
<div className="App">
<Route path="/" exact component={WebChatView} />
</div>
</Router>
);
}
}
export default App;
webChatView.js: Renders the web chat page (with some necessary styling)
import React, { Component } from 'react';
import WebChatView from './webchatView';
const FragmentStyling = {
'container': {
'display': 'flex',
'justifyContent': 'center'
},
'div': {
'height': '40rem',
'minHeight': '20rem',
'width': '1200px',
'display': 'flex',
'justifyContent': 'space-around',
'marginTop': '2rem'
}
}
class WebChatView extends Component {
render() {
return (
<div style={FragmentStyling.container}>
<div style={FragmentStyling.div}>
<WebChatView id="webchat" role="main" />
</div >
</div>
)
}
}
export default WebChatView;
webchat.js: Several things to note:
Either import '#babel/polyfill' needs to be included or all the 'core-js' imports listed below. Babel recommends importing only the required polyfills (to keep package size down). Those shown below are what is needed. However, using the '#babel' option works, as well.
Simply using fetch as-is breaks due to compatibility issues. There may be other options, but the below 'whatwg-fetch' option works in both IE and Chrome. Others I tested did not.
'fetching' the token needs to be promise-based. Using async/await breaks React web chat in IE.
import 'core-js/es6/map';
import 'core-js/es6/promise'
import 'core-js/es6/set';
import 'core-js/es6/symbol';
import 'core-js/fn/array/find-index';
import 'core-js/fn/array/includes';
import 'core-js/fn/math/sign';
import 'core-js/fn/object/assign';
import 'core-js/fn/string/starts-with';
import { fetch as fetchPolyfill } from 'whatwg-fetch';
import React from 'react';
import ReactWebChat, { createDirectLine } from 'botframework-webchat';
export default class WebChat extends React.Component {
constructor(props) {
super(props);
this.state = {
directLine: null
};
}
componentDidMount() {
this.fetchToken();
}
fetchToken(token) {
fetchPolyfill('http://localhost:3500/directline/token', { method: 'POST' })
.then(res => res.json()) // expecting a json response
.then(json =>
this.setState(() => ({
directLine: createDirectLine(
{
token: json.token
}
)
}))
)
}
render() {
return (
this.state.directLine ?
<ReactWebChat
directLine={this.state.directLine}
/>
:
<div>Connecting to bot…</div>
)
}
}
index.html: The 'react-polyfill.min.js' package needs to be included and should precede any other scripts that might live here.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="//pitzcarraldo.github.io/react-polyfill/react-polyfill.min.js" charSet="UTF-8"></script>
<title>React Web App</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
webpack.config.js: The import 'script!react-polyfill' needs to be included at the top of this file.
import 'script!react-polyfill';
const path = require('path');
module.exports = {
entry: ['./src/index.js'],
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'main.js'
},
mode: 'development'
};

Load Google Place API in Gatsbyjs (Reactjs) project

I am trying to use the AutoComplete address service from Google Place API.
Found this library:
https://github.com/kenny-hibino/react-places-autocomplete#load-google-library
It asks for loading the library in my project:
https://github.com/kenny-hibino/react-places-autocomplete#getting-started
I would do it in the public/index.html if it's pure Reactjs project. However, the public/index.html in Gatsbyjs project will be deleted and re-generated every time when running:
Gatsby develop
command line.
How can I use the Google Place API in my Gatsbyjs project?
Update
I have tried 2 ways to achieve this.
Use React-Helmet in /layouts/index.js , here is how it looks like:
<Helmet>
<script src="https://maps.googleapis.com/maps/api/js?key={API}&libraries=places&callback=initAutocomplete" async defer></script>
</Helmet>
Put the script reference in the /public/index.html, which looks like this:
<!DOCTYPE html>
<html>
<head>
<meta charSet="utf-8" />
<meta http-equiv="x-ua-compatible" content="ie=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<title data-react-helmet="true"></title>
<script src="/socket.io/socket.io.js"></script>
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key={API_KEY}&libraries=places" async defer ></script>
</head>
<body>
<div id="___gatsby"></div>
<script src="/commons.js"></script>
</body>
</html>
For the 1st solution, every time after I refresh my page, the project throws an error asking for loading the Google JavaScript Map API.
For the 2nd solution, every time after I re-start the Gatsby by the command line: gatsby develop
it re-generates the index.html which flushes away my JavaScript reference in it.
You shouldn't modify any files in the public forlder with GatsbyJS.
Instead, I recommend you to customize your html.js file.
To do so, first run:
cp .cache/default-html.js src/html.js
You should have the html.js file in /src/html.js.
Now you can put your <script> tag within the <head>.
Update Feb 24, 2020
Here's a more modern implementation using React hooks with some performance optimizations based on React.memo and a custom shouldUpdate function. See this blog post for details.
import { functions, isEqual, omit } from 'lodash'
import React, { useState, useEffect, useRef } from 'react'
function Map({ options, onMount, className, onMountProps }) {
const ref = useRef()
const [map, setMap] = useState()
useEffect(() => {
// The Map constructor modifies its options object in place by adding
// a mapTypeId with default value 'roadmap'. This confuses shouldNotUpdate.
// { ...options } prevents this by passing in a copy.
const onLoad = () =>
setMap(new window.google.maps.Map(ref.current, { ...options }))
if (!window.google) {
const script = document.createElement(`script`)
script.src = `https://maps.googleapis.com/maps/api/js?key=` + YOUR_API_KEY
document.head.append(script)
script.addEventListener(`load`, onLoad)
return () => script.removeEventListener(`load`, onLoad)
} else onLoad()
}, [options])
if (map && typeof onMount === `function`) onMount(map, onMountProps)
return (
<div
style={{ height: `60vh`, margin: ` 1em 0`, borderRadius: ` 0.5em` }}
{...{ ref, className }}
/>
)
}
function shouldNotUpdate(props, nextProps) {
const [funcs, nextFuncs] = [functions(props), functions(nextProps)]
const noPropChange = isEqual(omit(props, funcs), omit(nextProps, nextFuncs))
const noFuncChange =
funcs.length === nextFuncs.length &&
funcs.every(fn => props[fn].toString() === nextProps[fn].toString())
return noPropChange && noFuncChange
}
export default React.memo(Map, shouldNotUpdate)
Map.defaultProps = {
options: {
center: { lat: 48, lng: 8 },
zoom: 5,
},
}
Old Answer
Using html.js
Modifying src/html.js like so (as Nenu suggests) is one option.
import React, { Component } from 'react'
import PropTypes from 'prop-types'
export default class HTML extends Component {
render() {
return (
<html {...this.props.htmlAttributes}>
<head>
<meta charSet="utf-8" />
<meta httpEquiv="x-ua-compatible" content="ie=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
{this.props.headComponents}
</head>
<body {...this.props.bodyAttributes}>
{this.props.preBodyComponents}
<div
key={`body`}
id="___gatsby"
dangerouslySetInnerHTML={{ __html: this.props.body }}
/>
{this.props.postBodyComponents}
// MODIFICATION // ===================
<script
src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY"
async
defer
/>
// ===================
</body>
</html>
)
}
}
HTML.propTypes = {
htmlAttributes: PropTypes.object,
headComponents: PropTypes.array,
bodyAttributes: PropTypes.object,
preBodyComponents: PropTypes.array,
body: PropTypes.string,
postBodyComponents: PropTypes.array,
}
Then you can access the Google Maps API anywhere in your project from window.google.maps.(Map|Marker|etc.).
The React way
To me that felt a little anachronistic, though. If you want a reusable React component that you can import into any page or template as import Map from './Map', I suggest this instead. (Hint: See update below for equivalent function component.)
// src/components/Map.js
import React, { Component } from 'react'
export default class Map extends Component {
onLoad = () => {
const map = new window.google.maps.Map(
document.getElementById(this.props.id),
this.props.options
)
this.props.onMount(map)
}
componentDidMount() {
if (!window.google) {
const script = document.createElement('script')
script.type = 'text/javascript'
script.src = `https://maps.google.com/maps/api/js?key=YOUR_API_KEY`
const headScript = document.getElementsByTagName('script')[0]
headScript.parentNode.insertBefore(script, headScript)
script.addEventListener('load', () => {
this.onLoad()
})
} else {
this.onLoad()
}
}
render() {
return <div style={{ height: `50vh` }} id={this.props.id} />
}
}
Use it like so:
// src/pages/contact.js
import React from 'react'
import Map from '../components/Map'
const center = { lat: 50, lng: 10 }
const mapProps = {
options: {
center,
zoom: 8,
},
onMount: map => {
new window.google.maps.Marker({
position: center,
map,
title: 'Europe',
})
},
}
export default function Contact() {
return (
<>
<h1>Contact</h1>
<Map id="contactMap" {...mapProps} />
</>
)
}
What woked for me was to create a gatsby-ssr.js file in the root of my project, and then include the script there, like this:
import React from "react"
export function onRenderBody({ setHeadComponents }) {
setHeadComponents([
<script
key="abc"
type="text/javascript"
src={`https://maps.googleapis.com/maps/api/js?key=${process.env.GATSBY_API_KEY}&libraries=places`}
/>,
])
}
Don't forget to include GATSBY_API_KEY or whatever you want to call it in your .env.development and .env.production files:
GATSBY_API_KEY=...

react-helmet outputting empty strings on server-side

I am using react-helmet and on the client all is good in the inspect window and the tags are being outputted correctly. However, when I boot up in production and the SSR kicks in the tags aren't shown in the source and I'm getting no errors at all.
I tried logging the 'stringified' title tag too and got:
<title data-react-helmet="true"></title>
Here is some code:
This is one of the page components where I'm setting the tags from, the 3 page components are all set up identically to this. (I've simplified the components render function and data object as they are quite large and I'm sure these aren't at fault.)
import React, { Component } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { Link } from 'react-router-dom';
import { Helmet } from 'react-helmet';
// Components
import WorkGrid from 'universal/components/Grid';
import Wrapper from 'universal/components/Wrapper';
import Container from 'universal/components/Container';
import Hero from 'universal/components/Hero';
import PageWrapper from 'universal/components/PageWrapper';
import GridHeader from 'universal/components/GridHeader';
const data = {};
class Work extends PageComponent {
render () {
return (
<PageWrapper ref="root">
<Helmet>
<title>Work</title>
<meta name="description" content="Work Description" />
</Helmet>
<h1>Work Page</h1>
</PageWrapper>
);
}
}
export default connect(state => ({
theme: state.ui.theme
}), { changeTheme }, null, { withRef: true })(Work);
This is some of the server code, specifically where the SSR goes down and I'm calling Helmet.renderStatic();
// Node Modules
import fs from 'fs';
import {basename, join} from 'path';
// Libraries
import React from 'react';
import {StaticRouter} from 'react-router';
import {renderToString} from 'react-dom/server';
// styled-components
import { ServerStyleSheet, ThemeProvider } from 'styled-components';
import { theme } from '../universal/constants';
// Redux
// import {push} from 'react-router-redux';
import createStore from 'data/redux/createStore.js';
import createHistory from 'history/createMemoryHistory';
import { Provider } from 'react-redux';
// Third Party Scripts
import * as thirdPartyScripts from './thirdPartyScripts.js';
// Helmet
import {Helmet} from 'react-helmet';
function renderApp(url, res, store, assets) {
const PROD = process.env.NODE_ENV === 'production';
const context = {};
const {
manifest,
app,
vendor
} = assets || {};
let state = store.getState();
const stylesheet = new ServerStyleSheet();
const initialState = `window.__INITIAL_STATE__ = ${JSON.stringify(state)}`;
const Layout = PROD ? require( '../../build/prerender.js') : () => {};
const root = PROD && renderToString(
stylesheet.collectStyles(
<Provider store={store}>
<ThemeProvider theme={theme}>
<StaticRouter location={url} context={context}>
<Layout />
</StaticRouter>
</ThemeProvider>
</Provider>
)
);
const styleTags = stylesheet.getStyleTags();
const seo = Helmet.renderStatic();
console.log(seo.title.toString());
const html = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
${seo.title.toString()}
${seo.meta.toString()}
${seo.link.toString()}
<link rel="shortcut icon" href="/favicon.ico">
<link rel="icon" sizes="16x16 32x32 64x64" href="/favicon.ico">
<link rel="apple-touch-icon" href="/favicon-57.png">
<link rel="apple-touch-icon" sizes="114x114" href="/favicon-114.png">
<link rel="apple-touch-icon" sizes="72x72" href="/favicon-72.png">
<link rel="apple-touch-icon" sizes="144x144" href="/favicon-144.png">
<link rel="apple-touch-icon" sizes="60x60" href="/favicon-60.png">
<link rel="apple-touch-icon" sizes="120x120" href="/favicon-120.png">
<link rel="apple-touch-icon" sizes="76x76" href="/favicon-76.png">
<link rel="apple-touch-icon" sizes="152x152" href="/favicon-152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/favicon-180.png">
<meta name="msapplication-TileColor" content="#FFFFFF">
<meta name="msapplication-TileImage" content="/favicon-144.png">
<meta name="msapplication-config" content="/browserconfig.xml">
${ styleTags }
${PROD ? '<link rel="stylesheet" href="/static/prerender.css" type="text/css" />' : ''}
<link href="${thirdPartyScripts.googleFont}" rel="stylesheet" type="text/css">
<script>${thirdPartyScripts.googleAnalytics}</script>
</head>
<body>
<script>${initialState}</script>
${PROD ? `<div id="root">${root}</div>` : '<div id="root"></div>'}
${PROD ? `<script>${manifest.text}</script>` : ''}
<script>${thirdPartyScripts.facebookPixel}</script>
<script async src="${thirdPartyScripts.googleAnalyticsSrc}"></script>
${PROD ? `<script src="${vendor.js}"></script>` : ''}
<script src="${PROD ? app.js : './static/app.js'}"></script>
</body>
</html>`;
res.send(html);
}
Also, I am using React Router v4 if that's of any help.
I found the solution to this the other week and thought I may as well update this so it can help anyone else having this problem...
Good news is it was surprisingly simple!
For me anyway it was down to the fact that I separate webpack bundles for the client and the server. So in layman's terms it was including react-helmet twice, once for the client and once for the server, meaning all the state holding the meta tags in the client side code didn't exist in the .rewind() call on the server.
Just add this to your server webpack config file
externals: ['react-helmet']

Resources