• A React primer • Setup local development environment • Break the app into components • React Router primer • Add routing to our app • Make the app universal • Extra: Production build 13:50
• A React primer • Setup local development environment • Break the app into components • React Router primer • Add routing to our app • Make the app universal • Extra: Production build 14:00
• A React primer • Setup local development environment • Break the app into components • React Router primer • Add routing to our app • Make the app universal • Extra: Production build 14:05
by a tree of components (like the DOM is made up by a tree of HTML tags) • Components can be created in different ways (pure functions, class syntax) • A component can include other components as children • Components content is defined in JSX • Components can receive data from the outside (props) • Components can manage internal data (state) • Components can be installed (rendered) in an HTML page • Generally you'll have one main component containing all the others in your page
} from 'react-dom'; const IAmAComponent = () => ( <div> <h1>This is a component as a pure function</h1> </div> ); render(<IAmAComponent />, document.getElementById('root'));
} from 'react-dom'; class IAmAnotherComponent extends React.Component { render() { return ( <div> <h1>This is a component created with ES6 classes</h1> </div> ) } } render(<IAmAnotherComponent />, document.getElementById('root'));
JavaScript • It can contain JavaScript expressions • It is "transpiled" to plain JavaScript using Babel • Can include regular HTML tags (they start with a lowercase character) • … or other components (they start with an uppercase character) • Can include regular HTML attributes … With some exceptions: ◦ class becomes className ◦ properties with hyphens becomes camelcase ( background-color -> backgroundColor )
3 components • Title component • Content component • Footer component Then create a component called Layout that contains all the 3 as shown aside Then render the Layout component on the page https://codesandbox.io/s/48ok2yv3z7 14:35
They are used to pass "input" data into components (from the parent component) • They allow to create "reusable" components import React from 'react'; import { render } from 'react-dom'; const PrintProps = (props) => ( <div> <h1>Received props</h1> <pre>{ JSON.stringify(props, null, 2) }</pre> </div> ) render(<PrintProps foo="bar" bar="baz" qoo="qoo" />, document.getElementById('root'));
component that prints "Hello NAME", where NAME is coming from a props called name Render the HelloWorld component on the page passing your name as prop https://codesandbox.io/s/5vmr4o2m2n 14:45
of your favourite CSS colors. Hint: create a component to visualize a single color and render it multiple times based on the data contained in an array of colors. Bonus: Do something special with the color " RebeccaPurple ". https://codesandbox.io/s/qqqz0n5z19 14:50
• A React primer • Setup local development environment • Break the app into components • React Router primer • Add routing to our app • Make the app universal • Extra: Production build 15:00
with the needed static resources from here: loige.link/jhw-static 2. Unzip 3. Copy the content of the unzipped folder ( static ) into your static folder
• A React primer • Setup local development environment • Break the app into components • React Router primer • Add routing to our app • Make the app universal • Extra: Production build 15:15-15:30 ☕
= props => ( <div className="app-container"> <header> <a href="/"> <img className="logo" src="/img/logo-judo-heroes.png" alt="Judo Heroes logo" /> </a> </header> <div className="app-content">{props.children}</div> <footer> <p> This is a demo app to showcase <strong>universal Javascript</strong> with <strong>React</strong> and <strong>Express</strong>. </p> </footer> </div> ); export default Layout; Props: • children (the element to render as main content) <Layout> <span>Your content here...</span> </Layout>
• A React primer • Setup local development environment • Break the app into components • React Router primer • Add routing to our app • Make the app universal • Extra: Production build 15:45
as your app is rendering • Universal Routing: Can resolve routes also while rendering on the server • Advanced features: ◦ Nested Routes ◦ Responsive Routes
• A React primer • Setup local development environment • Break the app into components • React Router primer • Add routing to our app • Make the app universal • Extra: Production build 16:10
=> ( <div className="not-found"> <h1>404</h1> <h2>Page not found!</h2> <p> <a href="/">Go back to the main page</a> </p> </div> ); export default NotFoundPage; import React from 'react'; import { Link } from 'react-router-dom'; export const NotFoundPage = () => ( <div className="not-found"> <h1>404</h1> <h2>Page not found!</h2> <p> <Link to="/">Go back to the main page</Link> </p> </div> ); export default NotFoundPage;
React from 'react'; import { Link } from 'react-router-dom'; … const AhtleteMenuLink = ({ to, label }) => ( <Link to={to}>{label}</Link> ); … export default AthletesMenu; import React from 'react'; import { Link, Route } from 'react-router-dom'; … const AhtleteMenuLink = ({ to, label }) => ( <Route path={to}> {({ match }) => ( <Link to={to} className={match ? 'active' : ''}> {label} </Link> )} </Route> ); … export default AthletesMenu; If we pass a function inside a Route we can render content. match will be true if the current path matches the route. This is active!
• A React primer • Setup local development environment • Break the app into components • React Router primer • Add routing to our app • Make the app universal • Extra: Production build 16:30
import { renderToString } from 'react-dom/server'; import { StaticRouter as Router } from 'react-router-dom'; import { App } from './components/App'; const ServerApp = () => ( <Router location="/" context={{}}> <App /> </Router> ); console.log(renderToString(<ServerApp/>)); StaticRouter is an implementation of React Router that accepts the location path as a prop.
server that can serve our pages with the React app already rendered (based on the current URL) We need a template first ( src/views/index.ejs ) <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Judo Heroes - A Universal JavaScript demo application with React</title> <link rel="stylesheet" href="/css/style.css"> </head> <body> <div id="main"><%- markup -%></div> <script src="/bundle.js"></script> </body> </html> This placeholder will be replaced with the markup rendered with React on the server side
'http'; import Express from 'express'; import React from 'react'; import { renderToString } from 'react-dom/server'; import { StaticRouter as Router } from 'react-router-dom'; import { App } from './components/App'; const app = new Express(); const server = new Server(app); app.set('view engine', 'ejs'); app.set('views', path.join(__dirname, 'views')); app.use(Express.static(path.join(__dirname, '..', 'dist'))); app.use(Express.static(path.join(__dirname, '..', 'static'))); app.get('*', (req, res) => { const context = {}; const markup = renderToString( <Router location={req.url} context={context}> <App /> </Router>, ); return res.render('index', { markup }); }); server.listen(3000, () => { return console.info('Server running on http://localhost:3000'); }); Setup Express App with templating and static assets Universal routing and rendering. req.url is used to pass the current URL to React Router. The resulting markup is embedded into our template index.ejs and returned as response. Starts the server on the port 3000 16:45
'react-router-dom'; export const NotFoundPage = () => ( <div className="not-found"> <h1>404</h1> <h2>Page not found!</h2> <p> <Link href="/"> Go back to the main page </Link> </p> </div> ); export default NotFoundPage; import React from 'react'; import { Link } from 'react-router-dom'; export class NotFoundPage extends React.Component { componentWillMount() { const { staticContext } = this.props; if (staticContext) { staticContext.is404 = true; } } render() { return (<div className="not-found"> <h1>404</h1> <h2>Page not found!</h2> <p> <Link to="/">Go back to the main page</Link> </p> </div> ); } } export default NotFoundPage; staticContext is available when rendering from StaticRouter and allows components to exchange arbitrary data will rendering
• A React primer • Setup local development environment • Break the app into components • React Router primer • Add routing to our app • Make the app universal • Extra: Production build
utility to compile the server npm i webpack-node-externals // build the client node_modules/.bin/webpack -p // build the server node_modules/.bin/webpack -p --config webpack.server.config.js // start the server node src/server-es5.js
• A React primer • Setup local development environment • Break the app into components • React Router primer • Add routing to our app • Make the app universal • Production build
Universal JavaScript (remember the discount ) • Create React App • Universal Create React App • Progressive Web Apps with React • React/Redux Universal boilerplate with HMR • The code for Judo Heroes (V2) - Remember to STAR this repo