ff-stream-web

git clone git://archive.git.mtrnord.blog/MTRNord/ff-stream-web.git
Log | Files | Refs | README | LICENSE

commit 4495f49df732c78e46347b8df5aaed27b96a302f
parent 543d650b7873fbc193aabd6e2a09a1c5123d543e
Author: Konstantin Tarkus <koistya@gmail.com>
Date:   Thu, 10 Nov 2016 21:51:33 +0300

Move Layout component to routes (#959)

Unfortunately, in the current version of React, changing the top-level route to another type (even if the child UI tree is almost the same) will result in React tearing down that tree and building a new one. With this fix, the type of the parent component for each page will stay the same as a user transitions from one page/screen to another. Fixes #960.
Diffstat:
Mpackage.json | 10+++++-----
Msrc/components/App.js | 11+++++++++--
Msrc/routes/admin/Admin.js | 13+++++--------
Msrc/routes/admin/index.js | 3++-
Msrc/routes/contact/Contact.js | 13+++++--------
Msrc/routes/contact/index.js | 3++-
Msrc/routes/content/Content.js | 13+++++--------
Msrc/routes/content/index.js | 5+++--
Msrc/routes/home/Home.js | 33+++++++++++++++------------------
Msrc/routes/home/index.js | 3++-
Msrc/routes/index.js | 2+-
Msrc/routes/login/Login.js | 185+++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/routes/login/index.js | 3++-
Msrc/routes/notFound/NotFound.js | 13+++++--------
Msrc/routes/notFound/index.js | 3++-
Msrc/routes/register/Register.js | 13+++++--------
Msrc/routes/register/index.js | 3++-
17 files changed, 161 insertions(+), 168 deletions(-)

diff --git a/package.json b/package.json @@ -32,7 +32,7 @@ "query-string": "4.2.3", "react": "15.3.2", "react-dom": "15.3.2", - "sequelize": "3.24.8", + "sequelize": "3.25.0", "source-map-support": "0.4.6", "sqlite3": "3.1.8", "universal-router": "2.0.0", @@ -40,7 +40,7 @@ }, "devDependencies": { "assets-webpack-plugin": "^3.5.0", - "autoprefixer": "^6.5.2", + "autoprefixer": "^6.5.3", "babel-cli": "^6.18.0", "babel-core": "^6.18.2", "babel-eslint": "^7.1.0", @@ -57,7 +57,7 @@ "browser-sync": "^2.17.5", "chai": "^3.5.0", "css-loader": "^0.25.0", - "enzyme": "^2.5.1", + "enzyme": "^2.6.0", "eslint": "^3.9.1", "eslint-config-airbnb": "^13.0.0", "eslint-loader": "^1.6.1", @@ -81,7 +81,7 @@ "postcss-custom-properties": "^5.0.1", "postcss-custom-selectors": "^3.0.0", "postcss-flexbugs-fixes": "^2.0.0", - "postcss-loader": "^1.1.0", + "postcss-loader": "^1.1.1", "postcss-media-minmax": "^2.1.2", "postcss-nested": "^1.0.0", "postcss-nesting": "^2.3.1", @@ -94,7 +94,7 @@ "react-addons-test-utils": "15.3.2", "react-deep-force-update": "^2.0.1", "react-hot-loader": "^3.0.0-beta.6", - "redbox-react": "^1.3.2", + "redbox-react": "^1.3.3", "rimraf": "^2.5.4", "sinon": "^2.0.0-pre.3", "stylelint": "^7.5.0", diff --git a/src/components/App.js b/src/components/App.js @@ -28,9 +28,16 @@ const ContextType = { * store: createStore(), * }; * - * ReactDOM.render(<App context={context}><HomePage /></App>, container); + * ReactDOM.render( + * <App context={context}> + * <Layout> + * <LandingPage /> + * </Layout> + * </App>, + * container, + * ); */ -class App extends React.Component { +class App extends React.PureComponent { static propTypes = { context: PropTypes.shape(ContextType).isRequired, diff --git a/src/routes/admin/Admin.js b/src/routes/admin/Admin.js @@ -9,7 +9,6 @@ import React, { PropTypes } from 'react'; import withStyles from 'isomorphic-style-loader/lib/withStyles'; -import Layout from '../../components/Layout'; import s from './Admin.css'; class Admin extends React.Component { @@ -19,14 +18,12 @@ class Admin extends React.Component { render() { return ( - <Layout> - <div className={s.root}> - <div className={s.container}> - <h1>{this.props.title}</h1> - <p>...</p> - </div> + <div className={s.root}> + <div className={s.container}> + <h1>{this.props.title}</h1> + <p>...</p> </div> - </Layout> + </div> ); } } diff --git a/src/routes/admin/index.js b/src/routes/admin/index.js @@ -8,6 +8,7 @@ */ import React from 'react'; +import Layout from '../../components/Layout'; const title = 'Admin Page'; const isAdmin = false; @@ -28,7 +29,7 @@ export default { return { title, chunk: 'admin', - component: <Admin title={title} />, + component: <Layout><Admin title={title} /></Layout>, }; }, diff --git a/src/routes/contact/Contact.js b/src/routes/contact/Contact.js @@ -9,7 +9,6 @@ import React, { PropTypes } from 'react'; import withStyles from 'isomorphic-style-loader/lib/withStyles'; -import Layout from '../../components/Layout'; import s from './Contact.css'; class Contact extends React.Component { @@ -19,14 +18,12 @@ class Contact extends React.Component { render() { return ( - <Layout> - <div className={s.root}> - <div className={s.container}> - <h1>{this.props.title}</h1> - <p>...</p> - </div> + <div className={s.root}> + <div className={s.container}> + <h1>{this.props.title}</h1> + <p>...</p> </div> - </Layout> + </div> ); } } diff --git a/src/routes/contact/index.js b/src/routes/contact/index.js @@ -8,6 +8,7 @@ */ import React from 'react'; +import Layout from '../../components/Layout'; import Contact from './Contact'; const title = 'Contact Us'; @@ -19,7 +20,7 @@ export default { action() { return { title, - component: <Contact title={title} />, + component: <Layout><Contact title={title} /></Layout>, }; }, diff --git a/src/routes/content/Content.js b/src/routes/content/Content.js @@ -9,7 +9,6 @@ import React, { PropTypes } from 'react'; import withStyles from 'isomorphic-style-loader/lib/withStyles'; -import Layout from '../../components/Layout'; import s from './Content.css'; class Content extends React.Component { @@ -22,14 +21,12 @@ class Content extends React.Component { render() { const { path, title, content } = this.props; return ( - <Layout> - <div className={s.root}> - <div className={s.container}> - {title && path !== '/' && <h1>{title}</h1>} - <div dangerouslySetInnerHTML={{ __html: content }} /> - </div> + <div className={s.root}> + <div className={s.container}> + {title && path !== '/' && <h1>{title}</h1>} + <div dangerouslySetInnerHTML={{ __html: content }} /> </div> - </Layout> + </div> ); } } diff --git a/src/routes/content/index.js b/src/routes/content/index.js @@ -8,8 +8,9 @@ */ import React from 'react'; -import Content from './Content'; import fetch from '../../core/fetch'; +import Layout from '../../components/Layout'; +import Content from './Content'; export default { @@ -32,7 +33,7 @@ export default { if (!data || !data.content) return undefined; return { title: data.content.title, - component: <Content {...data.content} />, + component: <Layout><Content {...data.content} /></Layout>, }; }, diff --git a/src/routes/home/Home.js b/src/routes/home/Home.js @@ -9,7 +9,6 @@ import React, { PropTypes } from 'react'; import withStyles from 'isomorphic-style-loader/lib/withStyles'; -import Layout from '../../components/Layout'; import s from './Home.css'; class Home extends React.Component { @@ -23,24 +22,22 @@ class Home extends React.Component { render() { return ( - <Layout> - <div className={s.root}> - <div className={s.container}> - <h1 className={s.title}>React.js News</h1> - <ul className={s.news}> - {this.props.news.map((item, index) => ( - <li key={index} className={s.newsItem}> - <a href={item.link} className={s.newsTitle}>{item.title}</a> - <span - className={s.newsDesc} - dangerouslySetInnerHTML={{ __html: item.contentSnippet }} - /> - </li> - ))} - </ul> - </div> + <div className={s.root}> + <div className={s.container}> + <h1 className={s.title}>React.js News</h1> + <ul className={s.news}> + {this.props.news.map((item, index) => ( + <li key={index} className={s.newsItem}> + <a href={item.link} className={s.newsTitle}>{item.title}</a> + <span + className={s.newsDesc} + dangerouslySetInnerHTML={{ __html: item.contentSnippet }} + /> + </li> + ))} + </ul> </div> - </Layout> + </div> ); } } diff --git a/src/routes/home/index.js b/src/routes/home/index.js @@ -10,6 +10,7 @@ import React from 'react'; import Home from './Home'; import fetch from '../../core/fetch'; +import Layout from '../../components/Layout'; export default { @@ -31,7 +32,7 @@ export default { if (!data || !data.news) throw new Error('Failed to load the news feed.'); return { title: 'React Starter Kit', - component: <Home news={data.news} />, + component: <Layout><Home news={data.news} /></Layout>, }; }, diff --git a/src/routes/index.js b/src/routes/index.js @@ -22,7 +22,7 @@ export default { require('./register').default, require('./admin').default, - // place new routes before... + // Wildcard routes, e.g. { path: '*', ... } (must go last) require('./content').default, require('./notFound').default, ], diff --git a/src/routes/login/Login.js b/src/routes/login/Login.js @@ -9,7 +9,6 @@ import React, { PropTypes } from 'react'; import withStyles from 'isomorphic-style-loader/lib/withStyles'; -import Layout from '../../components/Layout'; import s from './Login.css'; class Login extends React.Component { @@ -19,106 +18,104 @@ class Login extends React.Component { render() { return ( - <Layout> - <div className={s.root}> - <div className={s.container}> - <h1>{this.props.title}</h1> - <p className={s.lead}>Log in with your username or company email address.</p> + <div className={s.root}> + <div className={s.container}> + <h1>{this.props.title}</h1> + <p className={s.lead}>Log in with your username or company email address.</p> + <div className={s.formGroup}> + <a className={s.facebook} href="/login/facebook"> + <svg + className={s.icon} + width="30" + height="30" + viewBox="0 0 30 30" + xmlns="http://www.w3.org/2000/svg" + > + <path + d="M22 16l1-5h-5V7c0-1.544.784-2 3-2h2V0h-4c-4.072 0-7 2.435-7 7v4H7v5h5v14h6V16h4z" + /> + </svg> + <span>Log in with Facebook</span> + </a> + </div> + <div className={s.formGroup}> + <a className={s.google} href="/login/google"> + <svg + className={s.icon} + width="30" + height="30" + viewBox="0 0 30 30" + xmlns="http://www.w3.org/2000/svg" + > + <path + d={'M30 13h-4V9h-2v4h-4v2h4v4h2v-4h4m-15 2s-2-1.15-2-2c0 0-.5-1.828 1-3 ' + + '1.537-1.2 3-3.035 3-5 0-2.336-1.046-5-3-6h3l2.387-1H10C5.835 0 2 3.345 2 7c0 ' + + '3.735 2.85 6.56 7.086 6.56.295 0 .58-.006.86-.025-.273.526-.47 1.12-.47 1.735 ' + + '0 1.037.817 2.042 1.523 2.73H9c-5.16 0-9 2.593-9 6 0 3.355 4.87 6 10.03 6 5.882 ' + + '0 9.97-3 9.97-7 0-2.69-2.545-4.264-5-6zm-4-4c-2.395 0-5.587-2.857-6-6C4.587 ' + + '3.856 6.607.93 9 1c2.394.07 4.603 2.908 5.017 6.052C14.43 10.195 13 13 11 ' + + '13zm-1 15c-3.566 0-7-1.29-7-4 0-2.658 3.434-5.038 7-5 .832.01 2 0 2 0 1 0 ' + + '2.88.88 4 2 1 1 1 2.674 1 3 0 3-1.986 4-7 4z'} + /> + </svg> + <span>Log in with Google</span> + </a> + </div> + <div className={s.formGroup}> + <a className={s.twitter} href="/login/twitter"> + <svg + className={s.icon} + width="30" + height="30" + viewBox="0 0 30 30" + xmlns="http://www.w3.org/2000/svg" + > + <path + d={'M30 6.708c-1.105.49-2.756 1.143-4 1.292 1.273-.762 2.54-2.56 ' + + '3-4-.97.577-2.087 1.355-3.227 1.773L25 5c-1.12-1.197-2.23-2-4-2-3.398 0-6 ' + + '2.602-6 6 0 .4.047.7.11.956L15 10C9 10 5.034 8.724 2 5c-.53.908-1 1.872-1 ' + + '3 0 2.136 1.348 3.894 3 5-1.01-.033-2.17-.542-3-1 0 2.98 4.186 6.432 7 7-1 ' + + '1-4.623.074-5 0 .784 2.447 3.31 3.95 6 4-2.105 1.648-4.647 2.51-7.53 2.51-.5 ' + + '0-.988-.03-1.47-.084C2.723 27.17 6.523 28 10 28c11.322 0 17-8.867 17-17 ' + + '0-.268.008-.736 0-1 1.2-.868 2.172-2.058 3-3.292z'} + /> + </svg> + <span>Log in with Twitter</span> + </a> + </div> + <strong className={s.lineThrough}>OR</strong> + <form method="post"> <div className={s.formGroup}> - <a className={s.facebook} href="/login/facebook"> - <svg - className={s.icon} - width="30" - height="30" - viewBox="0 0 30 30" - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M22 16l1-5h-5V7c0-1.544.784-2 3-2h2V0h-4c-4.072 0-7 2.435-7 7v4H7v5h5v14h6V16h4z" - /> - </svg> - <span>Log in with Facebook</span> - </a> + <label className={s.label} htmlFor="usernameOrEmail"> + Username or email address: + </label> + <input + className={s.input} + id="usernameOrEmail" + type="text" + name="usernameOrEmail" + autoFocus + /> </div> <div className={s.formGroup}> - <a className={s.google} href="/login/google"> - <svg - className={s.icon} - width="30" - height="30" - viewBox="0 0 30 30" - xmlns="http://www.w3.org/2000/svg" - > - <path - d={'M30 13h-4V9h-2v4h-4v2h4v4h2v-4h4m-15 2s-2-1.15-2-2c0 0-.5-1.828 1-3 ' + - '1.537-1.2 3-3.035 3-5 0-2.336-1.046-5-3-6h3l2.387-1H10C5.835 0 2 3.345 2 7c0 ' + - '3.735 2.85 6.56 7.086 6.56.295 0 .58-.006.86-.025-.273.526-.47 1.12-.47 1.735 ' + - '0 1.037.817 2.042 1.523 2.73H9c-5.16 0-9 2.593-9 6 0 3.355 4.87 6 10.03 6 5.882 ' + - '0 9.97-3 9.97-7 0-2.69-2.545-4.264-5-6zm-4-4c-2.395 0-5.587-2.857-6-6C4.587 ' + - '3.856 6.607.93 9 1c2.394.07 4.603 2.908 5.017 6.052C14.43 10.195 13 13 11 ' + - '13zm-1 15c-3.566 0-7-1.29-7-4 0-2.658 3.434-5.038 7-5 .832.01 2 0 2 0 1 0 ' + - '2.88.88 4 2 1 1 1 2.674 1 3 0 3-1.986 4-7 4z'} - /> - </svg> - <span>Log in with Google</span> - </a> + <label className={s.label} htmlFor="password"> + Password: + </label> + <input + className={s.input} + id="password" + type="password" + name="password" + /> </div> <div className={s.formGroup}> - <a className={s.twitter} href="/login/twitter"> - <svg - className={s.icon} - width="30" - height="30" - viewBox="0 0 30 30" - xmlns="http://www.w3.org/2000/svg" - > - <path - d={'M30 6.708c-1.105.49-2.756 1.143-4 1.292 1.273-.762 2.54-2.56 ' + - '3-4-.97.577-2.087 1.355-3.227 1.773L25 5c-1.12-1.197-2.23-2-4-2-3.398 0-6 ' + - '2.602-6 6 0 .4.047.7.11.956L15 10C9 10 5.034 8.724 2 5c-.53.908-1 1.872-1 ' + - '3 0 2.136 1.348 3.894 3 5-1.01-.033-2.17-.542-3-1 0 2.98 4.186 6.432 7 7-1 ' + - '1-4.623.074-5 0 .784 2.447 3.31 3.95 6 4-2.105 1.648-4.647 2.51-7.53 2.51-.5 ' + - '0-.988-.03-1.47-.084C2.723 27.17 6.523 28 10 28c11.322 0 17-8.867 17-17 ' + - '0-.268.008-.736 0-1 1.2-.868 2.172-2.058 3-3.292z'} - /> - </svg> - <span>Log in with Twitter</span> - </a> + <button className={s.button} type="submit"> + Log in + </button> </div> - <strong className={s.lineThrough}>OR</strong> - <form method="post"> - <div className={s.formGroup}> - <label className={s.label} htmlFor="usernameOrEmail"> - Username or email address: - </label> - <input - className={s.input} - id="usernameOrEmail" - type="text" - name="usernameOrEmail" - autoFocus - /> - </div> - <div className={s.formGroup}> - <label className={s.label} htmlFor="password"> - Password: - </label> - <input - className={s.input} - id="password" - type="password" - name="password" - /> - </div> - <div className={s.formGroup}> - <button className={s.button} type="submit"> - Log in - </button> - </div> - </form> - </div> + </form> </div> - </Layout> + </div> ); } } diff --git a/src/routes/login/index.js b/src/routes/login/index.js @@ -8,6 +8,7 @@ */ import React from 'react'; +import Layout from '../../components/Layout'; import Login from './Login'; const title = 'Log In'; @@ -19,7 +20,7 @@ export default { action() { return { title, - component: <Login title={title} />, + component: <Layout><Login title={title} /></Layout>, }; }, diff --git a/src/routes/notFound/NotFound.js b/src/routes/notFound/NotFound.js @@ -9,7 +9,6 @@ import React, { PropTypes } from 'react'; import withStyles from 'isomorphic-style-loader/lib/withStyles'; -import Layout from '../../components/Layout'; import s from './NotFound.css'; class NotFound extends React.Component { @@ -19,14 +18,12 @@ class NotFound extends React.Component { render() { return ( - <Layout full={false}> - <div className={s.root}> - <div className={s.container}> - <h1>{this.props.title}</h1> - <p>Sorry, the page you were trying to view does not exist.</p> - </div> + <div className={s.root}> + <div className={s.container}> + <h1>{this.props.title}</h1> + <p>Sorry, the page you were trying to view does not exist.</p> </div> - </Layout> + </div> ); } } diff --git a/src/routes/notFound/index.js b/src/routes/notFound/index.js @@ -8,6 +8,7 @@ */ import React from 'react'; +import Layout from '../../components/Layout'; import NotFound from './NotFound'; const title = 'Page Not Found'; @@ -19,7 +20,7 @@ export default { action() { return { title, - component: <NotFound title={title} />, + component: <Layout><NotFound title={title} /></Layout>, status: 404, }; }, diff --git a/src/routes/register/Register.js b/src/routes/register/Register.js @@ -9,7 +9,6 @@ import React, { PropTypes } from 'react'; import withStyles from 'isomorphic-style-loader/lib/withStyles'; -import Layout from '../../components/Layout'; import s from './Register.css'; class Register extends React.Component { @@ -19,14 +18,12 @@ class Register extends React.Component { render() { return ( - <Layout> - <div className={s.root}> - <div className={s.container}> - <h1>{this.props.title}</h1> - <p>...</p> - </div> + <div className={s.root}> + <div className={s.container}> + <h1>{this.props.title}</h1> + <p>...</p> </div> - </Layout> + </div> ); } } diff --git a/src/routes/register/index.js b/src/routes/register/index.js @@ -8,6 +8,7 @@ */ import React from 'react'; +import Layout from '../../components/Layout'; import Register from './Register'; const title = 'New User Registration'; @@ -19,7 +20,7 @@ export default { action() { return { title, - component: <Register title={title} />, + component: <Layout><Register title={title} /></Layout>, }; },