Scrimba: Learn React
Table of Contents
Intro
- The easiest way to learn something is the hard way
- learn by doing
- avoid “tutorial hell” by watching
- school: goal of learning is good grade. Here to be able to write react code.
- Repetition is your best friend when it comes to learn something
- Don’t binge the course
- Your brain needs rest. Take breaks often.
- Re-watch past lessons. Esp. when stuck.
- Ask community on discord, if in doubt.
- First thing to learn: how to think in react? React changes the game in terms of how you build the applications.
Build a React info site
- Why React?
- Allows to write composable code.
- It’s declarative (as opposed to imperative). How it is done is not required.
- Actively maintained by skilled people
- Hireable skill
JSX
- JSX - JavaScript XML. Flavour of javascript that looks like HTML.
- Allows to write HTML inside of JS.
console.log(JSXObj)
shows the JS structure behind it.- With JSX we need to make sure we’re returning only a single (parent) element.
- Dependencies required (
package.json
):react
react-dom
import React from "react" // make JSX syntax work; no longer required with react >= 17
import ReactDOM from "react-dom/client"
...
const root = ReactDOM.createRoot(document.getElementById("root"))
root.render(myComponent)
- A component is a function returning JSX UI. For components we use PascaCase for names.
- For styling use
className
instead ofclass
. - Vite takes care of:
- transpilation (Babel)
- Bundling (webpack, parcel, rollup, esbuild)
- Install nvm:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash
nvm install --lts
npm create vite@latest # name: `vite-react`, select `react` twice
cd vite-react
npm install
npm run dev
- teach the bundler will adapt to find actual images/css:
import logo from "./scrimba-log.png"
<img src={logo}/>
import "./App.css"
- Google Fonts. Put above the CSS link:
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;800&display=swap" rel="stylesheet">
- CSS for navbar:
* {
box-sizing: border-box;
}
body {
margin: 0;
font-family: Inter, sans-serif;
}
nav {
display: flex;
align-items: center;
height: 90px;
padding: 30px 25px;
}
.nav--logo_text, .nav--title {
margin: 0;
}
.nav--logo_text {
margin-right: auto;
}
.nav--icon {
height: 30px;
margin-right: 7px;
}
.main--title {
margin: 0;
letter-spacing: -0.05em;
}
.main--facts {
margin-top: 46px;
max-width: 400px;
}
.main--facts > li {
line-height: 19px;
padding-block: 10px;
}
.main--facts > li::marker {
font-size: 1.4rem;
}
main {
background-image: url("./images/react-icon-large.png");
background-repeat: no-repeat;
background-position: right 75%;
}
npm run build
- tell webpack to build our files and get them ready for prod.
Build a AirBnB experience clone
- Figma file
- Topics:
- Props
- Create components from an array
- use
{variable}
to interpolate variables in JSX. Anything within will be interpreted as regular JS code. Yet it is more readable to do the JS operations outside and only interpolate variables. - ES6 and later support destructuring:
const {img, name} = person
; within a function definition:function Contact({img, name}) {...}
- Conditional rendering:
{condition && <h1>Setup: {props.setup}</h1>}
- Pass on other datatypes than strings:
<Joke setup="..." votes={2} comments=[{author: "...", body: "...", liked: true}]/>
- Compute a html attribute
<img src={`../images/${props.img}`}/>
- Add a prop
key
and set it to something unique anytime when usingmap()
. - One of the reasons why React is popular is that it is just JS. No extra Markup language.
- Pass on all properties of an item using spread syntax:
<Card key={item.id} {...item}/>
Build a Meme generator
- Static web-page: read only, no changes to the data.
- Dynamic Web Apps: read and write. User can change the data that drives the webpage. Highly interactive.
- Topics:
- Event Listeners
- State
- Conditional Rendering
- Forms
- Side Effects
- Project figma
- Event handling: within the functional Component, define a handler function and pass it to appropriate attribute, e.g.:
onClick={clickHandler}
. - Props: come “from above”. Just like a function receiving arguments a component is not allowed to modify the props. Props are immutable.
- State: values that are managed by the component. Like a variable declared within a function to help you accomplish something. Values that a component can maintain between render cycles. State is mutable.
const [value, setter] = React.useState(DEFAULT_VALUE)
is one of the hooks in React.- When we care about the previous state, we provide a callback function to the
setter
function and it must return the new value. The one parameter to the callback is theprevValue
. This is so react can guarantee that we’ll receive the most recent value. E.g.setCount(prev => prev + 1)
. We should never modify the state but return a new value. - When we don’t care about the previous state we can use the
setter
directly, e.g.setCount(42)
. - Implicit return for object spread syntax:
setContact(prevContact => ({...prevContact, isFavorite: !prevContact.isFavorite}))
- Whenever state changes React will render the component where the state exists and any child component that relies on the state to work correctly.
- Pass the handler function as callback to the child to have a change done in the parent.
- If you need to pass a data from one component to the other, put it to the parent of the both. An in-built React solution: context. Other: redux.
- Rule of thumb: keep state as local as possible.
- CSS display:
display: inline-block; margin-right: 5px
- have elements placed next to each other. - React style:
<div style={{backgroundColor: "red"}}>
. Style must be a JS object and keys need to be camelCased. - You Probably Don’t Need Derived State - state being constructed from a prop.
array.findIndex(obj => obj.id === id)
to find the index of a matching obj in an array.- Form handling is one of React’s biggest weaknesses.
- Controlled Component: state you’re maintaining in your component should be the single source of truth. Each form component should have a
value
attribute, e.g.value={formData.firstName}
. - React team changed
<textarea></textarea>
to be a self-enclosed element, e.g.<textarea value={formData.comment} onChange={handleChange} name="comment" placeholder="Comments" />
- Checkbox:
<input type="checkbox" name="isFriendly" id="isFriendly" checked={formData.isFriendly} onChange={handleChange}/>
and the label follows:<label htmlFor="isFriendly">Are you friendly?<label/>
.handleChange()
needs to take the value ofchecked
attribute if the type ischeckbox
. - Radiobox:
checked
attribute needs to have a boolean value, thereforechecked={formData.employment === "unemployed"}
- Select & option:
<select id="favColor" value={formData.favColor} onChange={handleChange} name="favColor">
. - Form:
<form onSubmit={handleSubmit}>
. First thing we want to do inhandleSubmit(event)
is to callevent.preventDefault()
so the page is not refreshed. Then the form data can be submitted to an API.
- Controlled Component: state you’re maintaining in your component should be the single source of truth. Each form component should have a
// form handling fct
function handleChange(event) {
const {name, value, checked, type} = event.target
setFormData(prevFormData => {
return {
...prevFormData,
[name]: type === "checkbox" ? checked : value
}
})
}
- Star Wars API
- React’s primary tasks:
- Work with the DOM/browser to render the UI
- Manage state for us between render cycles
- Keep the UI updated whenever state changes occur
- NOT: (out)side effects! Anything outside of React’s rage. E.g.:
- localStorage.
- API/db interactions
- Subscriptions (.e.g. web sockets)
- Syncing 2 different internal states together
- Side Effects in React:
useEffect()
(complete guide) - tool to interact with outside of the React’s ecosystem.- 1st param: CB function. Everything inside is guaranteed to be run only after the component has been rendered. CB function always run after the first render.
- 2nd param (optional): dependencies array. Values if they changed from one render to other the 1st param will run.
[]
means it will run only once (no dependencies to track).
- You really never want to use an async CB function for the
React.useEffect
. An async function always returns a promise. So if you want an sync function inuseEffect()
define an async function and call it. Doing async operations directly would clash the point below: - Always cleanup things in the side effect (e.g. event listeners, WS connection etc.).
useEffect()
CB function can return a CB that will do the cleanup.
Build a notes app and a Tenzies game
Notes
- Whenever the state changes, React re-renders the whole component.
- Lazy state initialization. Instead of providing a value for
React.useState
provide a function. Any changes made after the initialization won’t re-run the function. event.stopPropagation()
stops propagating the click event to the parent.- JS optional chaining operator:
notes[0]?.id
. Returnid
orundefined
if the property before doesn’t exist. - Firebase Console
firestore.onSnapshot
creates a WS connection with the DB (=> cleanup || memory leak). It returns a function to be called for cleanup.- 2nd parameter to
onSnapshot
will be called always whenever there is an change to the 1st argument. - Debouncing: delay the request for a specified amount of time (e.g. 500ms)
Tenzies
- Figma
- NOTE: use better names (go simple). Learn the domain vocabulary before coding.
- Keeping two internal peaces of state in-sync with each other is a good reason to use
React.useEffect
- nanoid - unique string ID generator.