bundling • Babel for transpiling • Autoprefixing CSS with PostCSS (browser compatibility) • ESLint for linting • Jest for testing • Development server for with hot reloading • Build scripts for production • React, JSX, ES6 • Rollup • Esbuild (can be used with SWC or Babel) • ESLint is an option • Jest is an option 9
• Next.js (2016) • Remix • Gatsby • Learning curve for React maybe harder, from Next.js • To effectively use Next.js, it helps to be familiar with JavaScript, React, and related web development concepts. • So you should know React before learning Next.js! • Other alternative, maybe good for learning (2020): https://vitejs.dev 10
React React React Vanilla JS, React, Vue, etc. Server-Side Rendering Built-in Built-in Via plugins Not built-in Via plugins or SvelteKit Static Site Generation Built-in Built-in Built-in Manual (e.g., prerender) Via plugins or SvelteKit Client-Side Rendering Built-in Built-in Built-in Built-in Built-in Data Fetching getServerSideProps, getStaticProps load function in routes GraphQL, source plugins Fetch, Axios, etc. Fetch, Axios, etc. Routing File-system based File-system based File-system & GraphQL React Router, etc. File-system or manual API Support API routes in /api Route layouts & loaders Serverless Functions Manual setup Manual setup Styling Any CSS-in-JS or CSS/SASS Any CSS-in-JS or CSS/SASS Any CSS-in-JS or CSS/SASS Any CSS-in-JS or CSS/SASS Any CSS-in-JS or CSS/SASS Plugin Ecosystem Next.js plugins Mostly native React Rich Gatsby Plugin Ecosystem Limited to npm packages Vite plugins Community & Adoption Large Growing Large Very Large Growing Performance Optimization Automatic via Vercel Optimized out-of- the-box Optimized, especially for images Manual Fast (uses native ESM) Learning Curve Moderate Moderate to High Moderate Easy Moderate Use Case Universal (SSR, SSG, CSR) Universal (SSR, SSG, CSR) focus on fast navigation SSG: Mostly static site generation, good for blogs, docs CSR CSR, optimized for speed
JS handles the rendering of the UI in browser • Slower initial load; content fetched via JavaScript. • Search Engine Optimization less optimal, but improving. • Less server resource usage; more client CPU usage. 12
and CSR • Optionally: Server creates pre-rendered HTML and serves it to client • Client will have JS which will do interactivity • HTML generated on the server for each request. • Initial load faster; content immediately available. • SEO-friendly. • Requires server resources for rendering. 13
=> { axios.get('/api/data') .then(response => { setData(response.data); }); }, []); return ( <div> {data ? <h1>{data.message}</h1> : <p>Loading...</p>} </div> ); } 14 1. The page initially loads with a "Loading..." message. 2. An API request is made to /api/data. 3. Once data is received, it replaces "Loading..." with the actual data.
axios.get('http://localhost:3000/api/data'); return { props: { data: response.data } }; } const HomePage = ({ data }) => { return ( <div> <h1>{data.message}</h1> </div> ); }; 15 1.Before the page is rendered, getServerSideProps fetches data from /api/data. 2.The data is passed as a prop to the component. 3.The server sends a fully rendered HTML page with the data included. => Faster initial load => Better search engine optimization
faster than CRA in terms of both build time and development server startup time. • Ecosystem: CRA has a larger ecosystem and more community support, as it has been around for longer and is more widely used. • Features: CRA provides many features out of the box, including a development server, a production build script, and preconfigured ESLint and Babel settings. Vite, on the other hand, provides a minimalistic set of features out of the box and allows you to add additional plugins as needed. • Flexibility: Vite is more flexible than CRA, as it allows you to use different build tools and frameworks, not just React. Vite supports Vue.js, Svelte, and vanilla JavaScript, while CRA is specifically designed for React. 16
EcmaScript that browsers understand • Also Babel understands JSX which is heavily used in React • JSX is an extension to JavaScript • Easiest way to get babel is just to add • <script src="https://unpkg.com/babel- standalone@6/babel.min.js"></script> 19
methods explicitly defined. • Requires this keyword for state and props. • Use if you need lifecycle methods like componentDidMount. • Functional Components • Functional Components • Modern, less verbose. • Hooks provide lifecycle and state features. • Easier to test and maintain. • Recommended for new projects. 24
a component • A component let's you split the UI into reusable pieces. The component can be • Function component • Class component • To declare a function component • Function is written with capital letter • Returns react element • Usually accepts object argument 30
} ReactDOM.render( <Link link="http://www.tuni.fi" text="tuni"/>, document.getElementById('root') ); properties = {"link": "http://www.tuni.fi", "text": "uta"} properties are read only, do not try to modify them 31
is created from Clock constructor(props) { super(props); console.log("constructor") } // When Clock is rendered to the DOM componentDidMount() { console.log("componentDidMount") } // When Clock is removed from the DOM componentWillUnmount() { console.log("componentWillUnmount") } render() { console.log("render") let time = new Date().toLocaleTimeString() return (<div>{time}</div>); } } ReactDOM.render( <Clock />, document.getElementById('root') ); 39
componentDidMount() { // invoke this.tick for every 1 sec this.timer = setInterval(this.tick, 1000); } tick() { this.time = new Date().toLocaleTimeString() } componentWillUnmount() { clearInterval(this.timer); } render() { console.log("render") return (<div>{this.time}</div>); } } ReactDOM.render( <Clock />, document.getElementById('root') ); 1) will call tick() 2) tick will initalize time 3) Clock is rendered with time 4) Will set interval and invoke tick() for every 1 sec 5) Called for every 1 sec NOT working! Clock is not updating! 40
sec this.timer = setInterval(this.tick, 1000); } tick() { console.log(this); this.time = new Date().toLocaleTimeString() } this is window! It's not the clock object! So in here we are creating a global variable... 42
1 sec this.timer = setInterval(() => { this.tick() }, 1000); } If using arrow function, it does automatically the closure for "this". Arrow function contains "lexical this" feature! 44
1 sec this.timer = setInterval(this.tick.bind(this), 1000); } The bind will create copy of the original function and replaces the "this" in the function with the given object, which in this case is the component object ("this") 45
this.tick.bind(this) this.tick(); } componentDidMount() { // invoke this.tick for every 1 sec this.timer = setInterval(this.tick, 1000); } tick() { this.time = new Date().toLocaleTimeString() } componentWillUnmount() { clearInterval(this.timer); } render() { console.log("render") return (<div>{this.time}</div>); } } ReactDOM.render( <Clock />, document.getElementById('root') ); Replaces the tick function with a function that does not containg this keyword, instead this keyword is replaced with Clock object 46
() => { this.time = new Date().toLocaleTimeString() } this.tick(); } componentDidMount() { // invoke this.tick for every 1 sec this.timer = setInterval(this.tick, 1000); } tick() { this.time = new Date().toLocaleTimeString() } componentWillUnmount() { clearInterval(this.timer); } render() { console.log("render") return (<div>{this.time}</div>); } } ReactDOM.render( <Clock />, document.getElementById('root') ); If we move the function from Clock.prototype to Clock object itself which uses arrow syntax (lexical this), it will work also. 47 You can replace this syntax with class fields!
(you can do this only in constructor) • this.state.time = "something" • Instead of use the setState • this.setState({time: "something"}) • Setting the state may be asynchronous • State updates are merged • State should be capsulated into the component • By using props, state can be given to child component 54
= {time: new Date().toLocaleTimeString(), place: "Helsinki"} this.state = stateObject } componentDidMount() { this.timer = setInterval(this.tick, 1000); } tick = () => { let stateObject = {time: new Date().toLocaleTimeString()} this.setState(stateObject) } componentWillUnmount() { clearInterval(this.timer); } render() { return (<div>{this.state.time} {this.state.place}</div>); } } When setting new state with "time" the "place" is still intact! This is merging 55
Date().toLocaleTimeString(), place: "Helsinki" } componentDidMount() { this.timer = setInterval(this.tick.bind(this), 1000); } tick = () => { let stateObject = { time: new Date().toLocaleTimeString() }; this.setState(stateObject); } componentWillUnmount() { clearInterval(this.timer); } render() { return ( <div> {this.state.time} {this.state.place} </div> ); } } You can also use ESNext with class fields for state and omit the constructor 56
API for AJAX • You can easily combine Fetch and React • Fetch API is asynchronous and uses Promises: fetch(url).then((response) => { return response.json() } ) .then((jsonObject) => { console.log(jsonObject) }); 57
console.log('click') } render() { return (<button onClick={this.buttonClicked}>Click</button>); } } Calling the buttonClicked Notice camelCase! event (SyntheticEvent) brings you information about the event 60
console.log('click') } render() { return (<a onClick={this.linkClicked} href="">Link</a>); } } Preventing the default behaviour link usually opens another page 61
constructor(props) { super(props) } linkClicked(event) { event.preventDefault(); console.log(this) } render() { return (<a onClick={this.linkClicked.bind(this)} href="">Link</a>); } } Now this refers to Link object in the linkClicked - method 64
{name: ''} componentDidMount() { console.log('mount') } componentDidUpdate(prevProps, prevStat) { console.log('update') } render() { return <p>{this.state.name}</p> } } 85 This is called now several times! Only one time
arr = React.useState("initial text"); const text = arr[0]; const setText = arr[1]; return ( <div> <p>{text}</p> <button onClick={() => setText("hello")}>Click me</button> </div> ); } 91 Will return a array containing initial state value and a function for updating state When calling the function the state changes and rerender happens
componentDidMount, componentWillUnmount • By using Effect Hooks you can implement the functionality of these • You can do also more stuff with it using "dependencies" • Effect will react when some state value changes 102
update() { setTime(new Date().toString()) } React.useEffect(() => { let interval = setInterval(update, 1000) return () => clearInterval(interval) }) return <p>{time}</p> } 103 useEffect is similar to didMount AND didUpdate, happens after render If this function returns a function it is called when Clock is cleared from dom this will change state, useEffect called again...
update() { setTime(new Date().toString()) } React.useEffect(() => { let interval = setInterval(update, 1000) return () => clearInterval(interval) }, []) return <p>{time}</p> } 104 "dependencies", call effect function if depency value change. By giving empty array, it will be called only once
''}) // Similar to componentDidMount AND componentDidUpdate React.useEffect(() => { axios.get(`https://swapi.dev/api/people/${props.id}/`).then(hr => { setCharacter(hr.data) }) }) console.log('render: ' + new Date().toString()) return <p>{character.name}</p> } 117 Changing the state will trigger useEffect again! Eternal loop!
React.useState({name: ''}) // Similar to componentDidMount AND componentDidUpdate React.useEffect(() => { axios.get(`https://swapi.dev/api/people/${props.id}/`).then(hr => { setCharacter(hr.data) }) }, [props.id]) console.log('render: ' + new Date().toString()) return <p>{character.name}</p> } 118 Every time a props.id is changed trigger the effect
let names = ['jack', 'tina', 'paul', 'susanne'] let index = Math.floor(Math.random() * names.length) let randomName = names[index] console.log(randomName) } render() { return <button onClick={this.generate}>Generate Random Name</button> } } class DisplayRandomName extends React.Component { render() { return <p>Display Random Name</p> } } class Parent extends React.Component { render() { return <div><RandomGenerator/><DisplayRandomName/></div> } } 128 Generates random name This component wants to display the random name
let names = ['jack', 'tina', 'paul', 'susanne'] let index = Math.floor(Math.random() * names.length) let randomName = names[index] console.log(randomName) } render() { return <button onClick={this.generate}>Generate Random Name</button> } } class DisplayRandomName extends React.Component { render() { return <p>Display Random Name</p> } } class Parent extends React.Component { render() { return <div><RandomGenerator/><DisplayRandomName/></div> } } 129 When button clicked random name is in console. How to pass this to DisplayRandomName component?
let names = ['jack', 'tina', 'paul', 'susanne'] let index = Math.floor(Math.random() * names.length) let randomName = names[index] this.props.buttonClicked(randomName) } render() { return <button onClick={this.generate}>Generate Random Name</button> } } class DisplayRandomName extends React.Component { render() { return <p>Display Random Name</p> } } class Parent extends React.Component { clicked = (name) => { console.log(name) } render() { return <div><RandomGenerator buttonClicked={this.clicked}/><DisplayRandomName/></div> } } 130 .. And the function is passed here We have a function in the props now…
React app with no configuration. • Zero Config: Automatically handles bundling, linting, and other tasks. • Ejectable: Can "eject" to customize build scripts, but this is a one-way operation. • Regular Updates: Maintained by Facebook, ensuring compatibility with newer React features. • Disadvantages: • SPA Focused: Not optimized for server-side rendering or static site generation. • Limited Flexibility: Requires ejecting for advanced customizations, which can make the setup complex. • Larger Bundles: Without manual optimization, bundles might be larger compared to other tools. 144
generation, and client-side rendering. • File-based Routing: Automatic route creation based on the pages directory. • Built-in API Routes: Simplifies backend API creation with Node.js. • Performance Optimizations: Automatic code-splitting and image optimization. • Developer Experience: Features like fast refresh enhance the development process. • Disadvantages: • Learning Curve: Requires understanding Next.js-specific life-cycle methods and features. • Configuration: While it's zero-config by default, custom setups (like with custom servers) can become complex. • Larger Node.js Server Footprint: If using server-side rendering features, deployment might need resources for a Node.js server. 145
Webpack and Babel • Webpack will help you with ECMAScript modules • Babel helps you to compile ES6 (and JSX) to older JS so it works on different browsers • To combine react, webpack and babel, use create-react-app • npx create-react-app my-app • cd my-app • npm start • And in the end (to compile for production) • npm run build 146
JavaScript to run this app. </noscript> <div id="root"></div> <!-- This HTML file is a template. If you open it directly in the browser, you will see an empty page. You can add webfonts, meta tags, or analytics to this file. The build step will place the bundled scripts into the <body> tag. To begin the development, run `npm start` or `yarn start`. To create a production bundle, use `npm run build` or `yarn build`. --> </body> 147
• There is no official routing package made by FB • React Router (v4) is one of the most used ones. • For browser install • npm install react-router-dom 151