I am following https://help.twitter.com/en/using-twitter/embed-twitter-feed for embedding timeline in the angular page. Only button renders but not the actual timeline.
The index.html looks like:
<body style="margin:0">
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<app-root></app-root>
</body>
app.component.html looks like below:
<a class="twitter-timeline"
href="https://twitter.com/TwitterDev/lists/national-parks?ref_src=twsrc%5Etfw">
A Twitter List by TwitterDev
</a>
Also tried things like app.component.ts:
ngOnInit(){
if ((<any>window).twttr.ready())
(<any>window).twttr.widgets.load();
}
But no luck
you need to load widgets.js script after twitter-timeline element is been render so if you place the script in index.html it is will load and the element hasn't render yet.
๐ the best way around it is to create a script tag dynamically after the element is rendered.
twitter component
export class TwitterComponent {
#Input() user:string;
constructor(private renderer2: Renderer2,private el: ElementRef) {}
ngAfterViewInit() {
let scriptEl = document.createElement('script');
scriptEl.src = "https://platform.twitter.com/widgets.js"
this.renderer2.appendChild(this.el.nativeElement, scriptEl);
}
}
template
<a class="twitter-timeline" href="https://twitter.com/{{user}}">Tweets by {{user}}</a>
app componenet template
<app-twitter [user]="name"></app-twitter>
angular twitter widgets โกโก
ngAfterViewInit() a lifecycle hook that is called after Angular has fully initialized a component's view.
Updated ๐ฅ๐ฅ
a simple soulution mention in this answer before by user named Bernardo Baumblatt
put the script link in the index.html
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8">
</script>
load the twitter widgets when ngAfterViewInit method call
ngAfterViewInit() {
// #ts-ignore
twttr.widgets.load();
}
in any case the script has not loaded yet you will got an error like ๐ twttr is not defined ๐ so download the widgets.js script and include it to your project by using import
main.ts
import './app/widgets.js'
demo ๐ฅ๐ฅ
I had a requirement of dynamically rendering timelines based on different twitter timelines.
I found a workaround by creating a variable in the constructor that stores the href based on the twitter username .
So for example if your link is "https://twitter.com/TwitterDev/lists/national-parks?ref_src=twsrc%5Etfw"
, you just put this in the constructor in a previously defined global variable , say "embedLink"
such as in your ts component:
#Component({
selector: 'app-tree-dashboard',
templateUrl: './tree-dashboard.component.html',
styleUrls: ['./tree-dashboard.component.css']
})
export class TreeDashboardComponent implements OnInit,AfterViewInit {
embedLink='';
constructor(private matIconRegistry: MatIconRegistry,
) {
this.embedLink= "https://twitter.com/TwitterDev/lists/national-parksref_src=twsrc%5Etfw"
}};
and then in your HTML :
<a class="twitter-timeline" href={{embedLink}}></a>
And lastly you only need to add the script in index.html which you have done already.
So you're good to go!
Below is my code. I'm creating blank website so I think it's should not be a problem. What I think is maybe the order of the script in index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Twitter</title>
<base href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
</head>
<body>
<app-root></app-root>
</body>
<script
async
src="https://platform.twitter.com/widgets.js"
charset="utf-8"
></script>
</html>
In my app.component.html
<a class="twitter-timeline"
href="https://twitter.com/TwitterDev/lists/national-parks?ref_src=twsrc%5Etfw">
A Twitter List by TwitterDev
</a>
You can view my code here
I have just started using angular2 and I am facing some situation to organize my logic. I am actually refactoring backend theme that consists of the two main components i.e login view that is supposed to appear on page load and main dashboard that will appear on successful login. I have no problem with the main dashboard template because i have refactored all the code its working fine. However the main problem is with the login module because dashboard consist of the sidebar, header and maincontent area. My real problem is that how do I exclude sidebar, header on loading the login page which will going to be the startpoint of my app. To be more precise, can i use the layout for the login module which is independent to the dashboard module? Here is my current code for the dashboard.
I would really appreciate if anyone could help me structure this app in proper way.
P.S I am using node as a backend
index.html
<html>
<head>
<title>Angular 2 QuickStart</title>
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/reflect-metadata/Reflect.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<!-- 2. Configure SystemJS -->
<base href="/">
<script src="systemjs.config.js"></script>
<script>
System.import('app/main').catch(function(err){ console.error(err); });
</script>
</head>
<!-- 3. Display the application -->
<body>
<parent>
Loading...
</parent>
<!-- START SCRIPTS -->
<!-- START PLUGINS -->
</body>
</html>
app.component.ts
import { Component, NgZone } from '#angular/core';
import { HeaderComponent } from './header/header.component';
import { SidebarComponent } from './sidebar/sidebar.component';
import { AuthComponent } from './auth/auth.component';
import { ListComponent } from './blogs/list.component';
import {RouteConfig, ROUTER_DIRECTIVES, Router, AuxRoute} from '#angular/router-deprecated';
#Component({
selector: 'parent',
templateUrl:'app/main.html',
directives: [ROUTER_DIRECTIVES, HeaderComponent, SidebarComponent, AuthComponent]
})
#RouteConfig([
{ path: '/list', name: 'BlogList', component: ListComponent}
])
export class AppComponent {
constructor(private _router: Router , private _zone:NgZone){}
}
main.ts
import { bootstrap } from '#angular/platform-browser-dynamic';
import { AppComponent } from './app.component';
import {ROUTER_PROVIDERS} from '#angular/router-deprecated';
bootstrap(AppComponent,[ROUTER_PROVIDERS]);
import {NgZone, enableProdMode} from '#angular/core'
main.html
<div class="page-container">
<div class="page-sidebar">
<mysidebar>
</mysidebar>
</div>
<div class="page-content">
<myheader>
</myheader>
<!-- PAGE CONTENT WRAPPER -->
<div class="page-content-wrap">
<router-outlet></router-outlet>
</div>
</div>
</div>
You can accomplish this by using a Service
export class AppComponentService {
public showSidebar : boolean = true;
public showHeader : boolean = true;
}
If you add this service during bootstrap:
bootstrap(AppComponent,[ROUTER_PROVIDERS, AppComponentService ]);
You can inject this into your AppComponent:
export class AppComponent {
constructor(
private _router: Router,
private _zone:NgZone,
private _appService: AppComponentService
){}
}
And change your template to:
<div class="page-container">
<div class="page-sidebar">
<mysidebar *ngIf="_appService.showSidebar">
</mysidebar>
</div>
<div class="page-content">
<myheader *ngIf="_appService.showHeader">
</myheader>
<!-- PAGE CONTENT WRAPPER -->
<div class="page-content-wrap">
<router-outlet></router-outlet>
</div>
</div>
</div>
Within your LoginComponent you can inject the same singleton service, and play with it on routerOnActivate and routerOnDeactivate:
export class LoginComponent {
constructor(private _appService: AppComponentService){}
routerOnActivate() : void {
this._appService.showSidebar = false;
this._appService.showHeader = false;
}
routerOnDeactivate() : void {
this._appService.showSidebar = true;
this._appService.showHeader = true;
}
}
Can anyone point me if svg <use> can work in IE 11 and how, inside of Angular 2 component?
It works fine in Chrome but does not work in IE for me.
I did include svg4everybody.js library but if I use this inside of a component template or template url, it does not work.
Please let me know what I should do. Thanks you ver much
import {Component} from '#angular/core';
#Component({
selector: 'my-app',
template: `
<h1>My First Angular 2 App</h1>
<svg viewBox="0 0 32 32" width='150' height='150' fill='pink' role='img'>
<use xlink:href="app/sprites.svg#splitup"/>
</svg>
`
})
export class AppComponent { }
<html>
<head>
<title>Angular 2 QuickStart</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css">
<!-- Polyfill(s) for older browsers -->
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/reflect-metadata/Reflect.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="node_modules/svg4everybody/svg4everybody.js"></script>
<script src="systemjs.config.js"></script>
<script>
System.import('app').catch(function(err){ console.error(err); });
</script>
</head>
<body>
<my-app>Loading...</my-app>
</body>
</html>
Well, It's not related to IE11, supports it SVG or no. Problem is that, at the point, when svg4everybody.js is loaded and svg4everybody() method is called, your template isn't rendered in the DOM.
So, you will need to call svg4everybody() from component's ngOnInit method.
See this: Include External JavaScript Libraries In An Angular 2 TypeScript Project
is not supported on IE10, IE11. But inline svg will however work.
Therefore you should rely on a module to import the symbol into the dom as a standalone svg.
You can use the module: https://github.com/arkon/ng-inline-svg
With the [forceEvalStyles]="true" parameter for IE11.
This lib does not work with IE10, perhaps a reason is innerHTML not working on IE10 with SVG content.
Shims are available (I did not test the ng-inline-svg with them on IE10)
https://code.google.com/archive/p/innersvg/
https://www.npmjs.com/package/svg-innerhtml
In addition to David Gabrichidze anwser, it's possible to add svg4everyone with npm install.
npm install --save svg4everybody
Add script in angular.json
...
"scripts": ["./node_modules/svg4everybody/dist/svg4everybody.js"]
...
And then use it like this in app.component.ts:
import { Component, OnInit } from '#angular/core';
declare const svg4everybody: any;
#Component({
selector: 'app-root',
template: ''
})
export class AppComponent implements OnInit {
ngOnInit(): void {
// IE 11 external svg support
svg4everybody();
}
}
for the first time using angular2 , following the instruction from 5 minute Quickstart guide for angular 2.
everything is working good, means no error while run npm start
npm start image
but when i open
localhost:3000
it show Loading... text which is not expecting. according to this example content of index.html should reflects on this.
in console there is error :
EXCEPTION: TypeError: Cannot set property 'endSourceSpan' of null
main.ts
import { bootstrap } from '#angular/platform-browser-dynamic';
import { AppComponent } from './app.component';
bootstrap(AppComponent);
app.component.ts
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
template: 'My first Angular 2 App</h1>'
})
export class AppComponent {}
index.html
<html>
<head>
<title>Angular 2 QuickStart</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css">
<!-- 1. Load libraries -->
<!-- Polyfill(s) for older browsers -->
<script src="node_modules/es6-shim/es6-shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/reflect-metadata/Reflect.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<!-- 2. Configure SystemJS -->
<script src="systemjs.config.js"></script>
<script>
System.import('app').catch(function(err){ console.error(err); });
</script>
</head>
<!-- 3. Display the application -->
<body>
<my-app>Loading...</my-app>
</body>
</html>
Kindly help me what is going wrong.
I think that you have a problem in the template of your main component. For example a HTML element that isn't correctly closed:
template : '<div</div>'
See this issue for more details:
https://github.com/angular/angular/issues/7849
Edit
The problem is that your h1 isn't correct (no begin element):
#Component({
selector: 'my-app',
template: '<h1>My first Angular 2 App</h1>' // <------
})
export class AppComponent {}
You should check the port number of nodeserver shows in your terminal,
In Angular2 it'll be running in 4200.
ie ** NG Live Development Server is running on http://localhost:4200. **
Then open localhost with specified port in browser.
I'm trying to get an isomorphic Node.js, Express, Webpack, React app working. I'm getting the following error. Any suggestions on how to fix it?
Warning: React attempted to reuse markup in a container but the checksum was invalid. This generally means that you are using server rendering and the markup generated on the server was not what the client was expecting. React injected new markup to compensate which works but you have lost many of the benefits of server rendering. Instead, figure out why the markup being generated is different on the client or server:
(client) rgin:0;display:flex;-webkit-align-items:
(server) rgin:0;display:flex;align-items:center;j
warning # warning.js:45
ReactMount._mountImageIntoNode # ReactMount.js:807
wrapper # ReactPerf.js:66
mountComponentIntoNode # ReactMount.js:268
Mixin.perform # Transaction.js:136
batchedMountComponentIntoNode # ReactMount.js:282
Mixin.perform # Transaction.js:136
ReactDefaultBatchingStrategy.batchedUpdates # ReactDefaultBatchingStrategy.js:62
batchedUpdates # ReactUpdates.js:94
ReactMount._renderNewRootComponent # ReactMount.js:476
wrapper # ReactPerf.js:66
ReactMount._renderSubtreeIntoContainer # ReactMount.js:550
ReactMount.render # ReactMount.js:570
wrapper # ReactPerf.js:66
(anonymous function) # client.jsx:14
(anonymous function) # iso.js:120
each # iso.js:21
bootstrap # iso.js:111
(anonymous function) # client.jsx:12
__webpack_require__ # bootstrap d56606d95d659f2e05dc:19
(anonymous function) # bootstrap d56606d95d659f2e05dc:39
(anonymous function) # bootstrap d56606d95d659f2e05dc:39
This is what is being delivered by the server to the browser initially:
<!doctype html>
<html lang="">
<head>
<title>my title</title>
<meta name="apple-mobile-web-app-title" content="my title" data-react-helmet="true" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" data-react-helmet="true" />
<meta name="apple-mobile-web-app-capable" content="yes" data-react-helmet="true" />
<meta name="mobile-web-app-capable" content="yes" data-react-helmet="true" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" data-react-helmet="true" />
<meta name="description" content="my description." data-react-helmet="true" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" data-react-helmet="true" />
<meta charset="utf-8" data-react-helmet="true" />
<link rel="stylesheet" href="/assets/styles/reset.css" data-react-helmet="true" />
<link rel="stylesheet" href="/assets/styles/base.css" data-react-helmet="true" />
<link rel="stylesheet" href="/assets/styles/Carousel.css" data-react-helmet="true" />
<link rel="stylesheet" href="/assets/styles/main.css" data-react-helmet="true" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto+Condensed" type="text/css" data-react-helmet="true" />
<link rel="icon" href="/assets/185bb6f691241307862b331970a6bff1.ico" type="image/x-icon" data-react-helmet="true" />
SCRIPT
</head>
<body>
<script src="https://cdn.firebase.com/js/client/2.2.7/firebase.js"></script>
<script src="https://cdn.firebase.com/libs/reactfire/0.4.0/reactfire.min.js"></script>
<div class="app">
<div class="___iso-html___" data-key="_0"><div data-reactid=".1hkqsbm9n9c" data-react-checksum="794698749"><div data-reactid=".1hkqsbm9n9c.0"><div data-reactid=".1hkqsbm9n9c.0.$=10"></div><div style="position:fixed;z-index:2;top:0;left:0;right:0;height:60px;color:rgb(219,219,219);font-family:mainnextcondensed_ultralight;font-size:17px;overflow:hidden;" data-reactid=".1hkqsbm9n9c.0.$/=11"><div style="position:absolute;left:0;top:0;background-color:rgba(27,27,27,0.92);padding-right:35px;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=10"><div style="float:left;height:60px;width:13px;border-left:5px solid rgb(210,45,164);" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=10.$/=10"></div><div style="float:left;height:60px;width:227px;background-image:url(data:image/png;base64,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);background-repeat:no-repeat;background-position:center;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=10.$/=11"></div><div style="display:none;width:0;height:0;border-style:solid;border-width:6px 6px 0 6px;border-color:rgb(117,117,117) transparent transparent transparent;-webkit-transform:rotate(360deg);float:left;margin-left:6px;margin-top:26px;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=10.$/=12"></div></div><div style="position:absolute;top:0px;left:280px;width:340px;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=11"><div style="background-color:rgba(27,27,27,0.92);height:10px;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=11.$/=10"></div><div style="background-color:rgba(53,53,53,0.84);height:40px;position:relative;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=11.$/=11"><div style="position:absolute;top:0;bottom:0;left:0;right:0;padding:0;margin:0;display:flex;align-items:center;justify-content:center;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=11.$/=11.$=10"><div style="background-image:url('/assets/3bec3e57cb5ee05658440d21984fb7b7.png');background-repeat:no-repeat;background-position:-58px -194px;width:23px;height:22px;position:absolute;top:50%;left:10px;margin-top:-11px;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=11.$/=11.$=10.$icon"></div></div><div style="position:absolute;left:40px;right:40px;top:0px;bottom:0px;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=11.$/=11.$/=12"><input type="text" style="width:100%;height:100%;font-size:14px;font-family:mainnext_regular;background-color:transparent;color:#ffffff;" placeholder="SEARCH ARTISTS, TRACKS, ALBUMS" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=11.$/=11.$/=12.0"/></div></div><div style="background-color:rgba(27,27,27,0.92);height:10px;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=11.$/=12"></div></div><div style="position:absolute;top:0px;left:620px;right:0px;background-color:rgba(27,27,27,0.92);height:60px;line-height:60px;overflow:hidden;min-width:500px;padding-left:10px;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=12"><div style="position:absolute;top:0px;bottom:0px;right:0px;width:357px;padding-left:141px;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=12.0"><a class="" href="/import" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=12.0.$/=10"><div style="padding-left:40px;position:absolute;left:0px;top:10px;bottom:10px;cursor:pointer;line-height:40px;color:rgb(255,255,255);" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=12.0.$/=10.$import"><div style="position:absolute;top:0;bottom:0;left:0;right:0;padding:0;margin:0;display:flex;align-items:center;justify-content:center;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=12.0.$/=10.$import.$=10"><div style="background-image:url('/assets/3bec3e57cb5ee05658440d21984fb7b7.png');background-repeat:no-repeat;background-position:0px -194px;width:28px;height:28px;position:absolute;top:50%;left:0px;margin-top:-14px;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=12.0.$/=10.$import.$=10.$icon"></div></div><span data-reactid=".1hkqsbm9n9c.0.$/=11.$/=12.0.$/=10.$import.1">Import Playlists</span></div></a><div style="margin-left:10px;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=12.0.$admin/=1$admin"><div style="cursor:pointer;float:left;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=12.0.$admin/=1$admin.$login">Login</div></div></div></div></div></div><noscript data-reactid=".1hkqsbm9n9c.1"></noscript></div></div>
<div class="___iso-state___" data-key="_0" data-meta="{}" data-state=""{\"UserStore\":{\"user\":{\"authenticated\":false,\"isWaiting\":false}},\"SearchStore\":{\"focused\":false,\"input\":\"\",\"timeout\":null,\"searchRequests\":[],\"artists\":null,\"artistsFailed\":false,\"artistsLoading\":false,\"tracks\":null,\"tracksFailed\":false,\"tracksLoading\":false,\"albums\":null,\"albumsFailed\":false,\"albumsLoading\":false,\"playlists\":null,\"playlistsFailed\":false,\"playlistsLoading\":false,\"youtubes\":null,\"youtubesFailed\":false,\"youtubesLoading\":false,\"soundclouds\":null,\"soundcloudsFailed\":false,\"soundcloudsLoading\":false},\"PlayerStore\":{\"player\":null,\"playerSecond\":null,\"playingTrack\":null,\"playingTrackSecond\":null,\"videoId\":null,\"videoIdSecond\":null,\"makingPlayingTrackPlayable\":false,\"radio\":false,\"startSeconds\":0,\"current\":0,\"total\":0,\"perc\":0,\"currentSecond\":0,\"totalSecond\":0,\"percSecond\":0,\"playing\":false,\"playingSecond\":false,\"secondsListened\":0,\"secondsListenedSecond\":0,\"expand\":false,\"source\":null,\"tracksQueue\":[],\"tracksPrevQueue\":[],\"favorite\":false,\"random\":false,\"repeat\":false,\"mute\":false,\"volume\":100,\"mode\":\"standard\"},\"ImportStore\":{\"url\":\"\",\"error\":false,\"focused\":false,\"loading\":false,\"loaded\":false,\"playlist\":null}}""></div>
</div>
<!-- Google Analytics: change UA-XXXXX-X to be your site's ID -->
<!--
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-XXXXX-X', 'auto');
ga('send', 'pageview');
</script>
-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/fastclick/1.0.3/fastclick.min.js"></script>
<script type="text/javascript">
if ('addEventListener' in document) {
document.addEventListener('DOMContentLoaded', function() {
FastClick.attach(document.body);
}, false);
}
</script>
<script type="text/javascript" charset="utf-8" src="/assets/app.js"></script>
</body>
</html>
This is my server.jsx:
import Iso from 'iso';
import React from 'react';
import ReactDomServer from 'react-dom/server';
import { RoutingContext, match } from 'react-router'
import createLocation from 'history/lib/createLocation';
import alt from 'altInstance';
import routes from 'routes.jsx';
import html from 'base.html';
/*
* #param {AltObject} an instance of the Alt object
* #param {ReactObject} routes specified in react-router
* #param {Object} Data to bootstrap our altStores with
* #param {Object} req passed from Express/Koa server
*/
const renderToMarkup = (alt, state, req, res) => {
let markup, content;
let location = new createLocation(req.url);
alt.bootstrap(state);
match({ routes, location }, (error, redirectLocation, renderProps) => {
if (redirectLocation)
res.redirect(301, redirectLocation.pathname + redirectLocation.search)
else if (error)
res.status(500).send(error.message)
else if (renderProps == null)
res.status(404).send('Not found')
else
content = ReactDomServer.renderToString(<RoutingContext {...renderProps} />);
markup = Iso.render(content, alt.flush());
});
return markup;
};
/*
* Export render function to be used in server/config/routes.js
* We grab the state passed in from the server and the req object from Express/Koa
* and pass it into the Router.run function.
*/
export default function render(state, req, res) {
const markup = renderToMarkup(alt, state, req, res);
return html.replace('CONTENT', markup);
};
And this is my client.jsx:
import React from 'react';
import ReactDOM from 'react-dom';
import Iso from 'iso';
import createBrowserHistory from 'history/lib/createBrowserHistory';
import { Router } from 'react-router';
import alt from 'altInstance';
import routes from 'routes.jsx';
/*
* Client side bootstrap with iso and alt
*/
Iso.bootstrap((state, _, container) => {
alt.bootstrap(state);
ReactDOM.render(<Router history={createBrowserHistory()} children={routes} />, container);
});
And my routes.jsx:
import React from 'react';
import Route from 'react-router';
import App from 'components/App';
import ImportPlaylist from 'components/ImportPlaylist';
import Login from 'components/Login';
import Logout from 'components/Logout';
import Player from 'components/Player/Player';
import Test from 'components/Test';
export default (
<Route path="/" component={App}>
<Route path="login" component={Login} />
<Route path="logout" component={Logout} />
<Route name="test" path="test" component={Test} />
<Route name="import" path="import" component={ImportPlaylist} />
<Route name="player" path="/:playlist" component={Player} />
</Route>
);
Note: This applies to older versions of React. If you're using React 16, you should use ReactDOM.hydrate()
Also, the below suggestion will result in a client-side re-render, as suggested by one of the answers below.
This may sound crazily simple, but in your server-side template, wrap your React markup in an extra <div>:
<!-- hypothetical handlebars template -->
<section role="main" class="react-container"><div>{{{reactMarkup}}}</div></section>
Why does this work? On the client, React has a propensity to wrap its rendering of your root component with a superfluous div. ReactDOMServer.render doesn't seem to behave in this manner, thus when one renders into the same container isomorphically, the Adler-32 checksum of your DOM differs.
For those googling and coming here, one weird way of ending up with this issue is where you're not even using isomorphic rendering (i.e. not rendering anything on the server side). This happened with me when using a template with the HtmlWebpackPlugin to process an index.html file.
In my index.html file I already included the bundle.js file myself, and the above plugin also includes another bundle.js via a script-src. Make sure you're setting inject: false to your HtmlWebpackPlugin constructor.
For me killing nodejs completely and restarting worked
WARNING The popular answer here is not correct. What it is doing is removing the existing DOM entirely, and replacing it with a fresh render on the client. It means you lose the fast shallow render from React and are wasting perf, and as a consequence it also swallows the OP error, and any other errors you might have.
Your issue appears to be with CSS - if you are using autoprefixer and inline-styles that would explain your difference here.
The server side has rendered align-items:center and the client has realised it's in a webkit browser and automatically prefixed it for you to -webkit-align-items.
Please post more info about the CSS set up, and any component using inline-styles or similar.
If you are rendering your main content inside of a layout component, you will need to render the layout as static markup (no react attributes) so that the checksum of the content matches between the client and server.
Server:
app.get('/', (req, res) => {
// render the content to a string so it has the same checksum as on the client
// render the layout to static markup so that it does affect the checksum
// this ensures that rendering is isomorphic and client doesn't override server markup
const content = reactDomServer.renderToString(<MyContent />)
const html = '<!DOCTYPE html>' + reactDomServer.renderToStaticMarkup(<HtmlLayout content={content} />)
res.send(html)
})
HtmlLayout:
export default class HtmlLayout extends React.Component<any, any> {
public render () {
return (
<html lang='en'>
<head>
<meta charSet='utf-8' />
<meta name='viewport' content='width=device-width, initial-scale=1' />
<title>Untitled</title>
<link rel='stylesheet' href='/style/bundle.css' />
</head>
<body>
{ /* insert the content as a string so that it can be rendered separate with its own checksum for proper server-side rendering */ }
<div id='content' dangerouslySetInnerHTML={ {__html: this.props.content} } />
<script src='scripts/bundle.js'></script>
</body>
</html>
)
}
}
Client:
const root = document.getElementById('content')
DOM.render(<MyContent />, root)
Reference: http://jeffhandley.github.io/QuickReactions/20-final-cleanup
In my case the problem was caused by the fact that I was using MediaQuery component from 'react-responsive' without passing the 'value' property which is used by the component when it is not able to access the screen width (e.g. on the Server).
I came across this issue on an Isomorphic app I was working on. What worked for me is, believe it or not, Emptying cache and hard reloading the app on Chrome. Looked like the old DOM was somehow cached on the Browser :)