React

date
Nov 30, 2022
type
KnowledgeBase
year
slug
react
status
Published
tags
React
JavaScript
summary
All about React and React Router
💡
React makes it painless to create interactive UIs on the web. Design simple views for each state in your application, and React will efficiently update and render just the right components when your data changes.
React Router
React Router
Once you know your way around React you might want to step up to Next.js

Set up

Option A: Create a starter project with npx create-react-app

Set up a project with npx create-react-app my-app (https://reactjs.org/docs/create-a-new-react-app.html)
Or if you prefer yarn, then yarn create react-app my-app
notion imagenotion image
This creates a basic React project from the default template with everything you need.
There are many other templates as well.
  • Minimal (even more minimal) npx create-react-app my-app --template minimal
  • Minimal with Typescript: npx create-react-app my-app --template minimal-typescript
  • Template with React and Redux and Typescript: npx create-react-app my-app --template redux-typescript
  • Popular React boilerplate: npx create-react-app my-app --template rb
Or maybe use this cleaned up version below:

Option B: Use this cleaned up starter project

(from the react course on Udemy)
  • run npm install
  • open folder in VSCode or WebStorm
  • Terminal > New Terminal (VSCode) or click on the Terminal tab on the bottom (WebStorm)
  • npm start
 
What this contains is basically this:
  • files in the public folder will be served directly via the web server
    • index.html is an HTML5 file with a <div id="root"></div> in the body. React will replace this with whatever content you make it render!
  • The src folder contains everything you want to bundle as a single package. Javascript, CSS, icons, JSON files, etc.
    • Bundling starts at index.js.
    • The main application file is usually called App.js
  • package.json is the main configuration file for the project, required by npm
index.html:
index.js:
App.js:

Option Nope: Minimal React without JSX - stupid idea. WHY?

This is stupid. Why wouldn’t we use JSX?! But oh well…
Put it in a folder somewhere and run a simple web server from that folder. There are many options:
  • run npx serve (node)
  • run npx http-server (node)
  • run python -m SimpleHTTPServer 3000 (Python 2)
  • run python -m http.server 3000 (Python 3)
  • run php -S localhots:3000 (PHP)

JSX

ℹ️
JSX Helps you write readable React code by inlining components so that they look like html-tags!
Full example of a React component:
This is a function component. And that’s the way to go. Don’t use class components anymore

Custom Components

Create component, export component, import component, use it.
Component name has to be uppercase! That’s als how you distinguish between built-in html components and React components: <CustomReactComponent> vs <html>
Components can only return one single element, so if you need to return multiple you can wrap them in a <div> or React’s <Fragment> (in newer versions a Fragment can just be <> </>)
Variables go in curly braces:
You can also call functions in curly braces, etc.:
Custom components can use properties (attributes) too:
And then use just it like you would in HTML:
The spread operator (…) is useful if you want to render all the properties…
How to deal with child nodes:
Use (abuse? 😉) how JS handles true/false by making our logical expressions return false or a react element (if isVerified is true it adds the Checkmark, otherwise it won’t):
Instead of a switch statement we can use an object with properties for the different cases resolving the different outcomes (the || makes sure any unknown cases show as deleted):
Show a list of options by mapping from a list of items
Fragments <></> are empty React elements that result in no HTML. Their only purpose is to group multiple other elements together. (You might need this, because a component can only return a single element, so if you want multiple, wrap them in a Fragment…)
Before React 16.2 you actually had to use <Fragment></Fragment>
Send tags through props via mixed arrays:

CSS

JSX uses camelCase where CSS uses hyphens font-size → fontSize
Where in HTML/CSS you would set
in JSX you have to do
example of applying multiple styles:
You can also put the styles into a variable and then apply it:
Or add css to a component by importing it at the top
in JSX, use className instead of class!

SASS

SASS
SASS
Add it to project
$ npm i -g sass
Then you can simply import sass files into components and it will work!
import './Countdown.scss';

Events

<button onClick={console.log('Click');}>
⚠️
In the example below, notice how we don’t have () when referring to clickHandler! If we had braces it would execute during rendering, not when clicked!
In the following example, note how the 3rd button fails and executes during rendering and not when clicked.
But if we can’t have (), then how can we send along parameters?! Turn it into an arrow function like this: (Note how the 3rd button also works on click now that we turned it into an arrow function!)

Gotchas

What things render as

Type
Output
“string”
"string”
"”
"”
3.4
"3.4”
0
"0”
NaN
"NaN”
Number.POSITIVE_INFINITY
"Infinity”
Number.NEGATIVE_INFINITY
"-Infinity”
true
"true”
false
"”
undefined
“”
null
“”
Notably only 4 of the things that are falsy render as empty strings, while 0 renders as “0” and NaN as “NaN”. This could lead to issues when you do stuff like this:
so you have to do this instead:

Multi-word Attributes

Multi-word attributes also switch to camelCase in JSX. clip-path → clipPath, fill-opacity → fillOpacity , etc.
And confusingly even multi-word attributes that are all lowercase in HTML, switch to camelCase: autoplay → autoPlay, allowfullscreen → allowFullscreen, or input field’s maxlength → maxLength

Reserved Names

class and for are reserved words in JavaScript, so in JSX you have to use className and htmlFor instead.
If you want to assign a CSS class:
If you need to create a label for a form element:

Boolean Attribute Values

The attribute value must be set as a JavaScript expression (inside {}) and not as a string!
If you omit a value after the property, React will set the value to true

Functional components

As mentioned at the top: Use only functional components - they are the way forward. Below we’ll look at class components 😷 and why we hate them now.
Example:
This HTML menu
notion imagenotion image
 
built with class components looked like this:
But built with functional components it looks like this! Much more compact and clean!
And if we’re extra cool we can even turn them into Arrow Function Components! (You know you want to…)
We simply create a function and return JSX, that’s it! Functional component!
If we need access to properties, we get it through the single argument passed to the function, which is a frozen object of properties.
Any value that can be executed as a function, that returns JSX, can be used as a component! You can even define them inline in another component:
we could even shorten it further using implicit return:

Destructuring Properties

Destructuring allows us to pick out the things we need from the single argument that is passed to our functional component:
We can also use this in normal functions btw:

Default Values

We can add default values by adding them to the function definition like this:
If we have some props we just want to pass through we can do this via Rest operator:

Hooks

ℹ️
Hooks are an umbrella term for a new kind of special function that “hooks” from your component into the React core machinery.
Functions that start with the word use* are hooks.
⚠️
When you use a hook in a component, you must always use that hook. And you must use the exact same hooks in the exact same order every time you render the component.
So if you use a hook you must always call it, you can’t wrap it in an if or exit out early - the hook must always be called!
There are 15 types of build-in hooks in React 18:
  • Stateful hooks (making components and applications stateful): useState, useReducer, useRef, useContext, useDeferredValue, useTransition
  • Effect hooks (running effects inside components): useEffect, useLayoutEffect
  • Memoization hooks (performance optimization via avoiding re-calculating values): useMemo, useCallback, useId
  • Library hooks (only really needed in larger projects): useDebugValue, useImperativeHandle, useInsertionEffect, useSyncExternalStore

State

ℹ️
State allows us to change values and have the relevant component redraw without reloading the page.
📙
We’re only dealing with state for functional components here. Class-based components work differently - see here
In general, any state used in a web application belongs to one of three categories:
  • Application data (data the user is working on)
  • UI state (which tab is active, whether a panel is collapsed or not, etc.)
  • Form data
 
Very simple API which consists of a single function, useState (a hook!)
  • takes an initial value
  • returns the current state and an update function
Simplest possible example: A counter. When the user clicks a button, we increment the counter and react updates the rendered element.
⚠️
Note how counter is a constant value, so calling setCounter doesn’t update it immediately! You can’t call setCounter and immediately continue as the value in counter will not update until after the next render! → Instead use an effect that reacts to counter changing!
More complex example where we’re setting a function instead of a value!

Previous Value

The setState function conveniently gives you the previous state:

State scope

State that spans multiple components. What if we want to access the value in one component, but update it in another?
In the code below, notice how the TodoApplication feeds the update function setHideDone up into the FilterButton. State is stored in TodoApplication and passed around to other components where applicable to render the result we need.

useRef - remember a value without re-rendering

Like with useState we can persist the state, but useRef doesn’t cause a re-render of the component! Just set the new value via .current

useRef - to get references to DOM elements

We will also use useRef to get references to DOM elements.
Below we create a variable ref with useRef(), then put it into the input tag and use the useEffect hook (configured to only trigger on mount) to focus that element. Specifically we auto-focus an input field when a component is mounted:
Or another example where we use ref to figure out which of two buttons was pressed. Both buttons call the same onClick function and it uses the ref increment.current to compare against the evt.target:

useContext

similar to useState, but useContext works in a store in a parent component somewhere up the component tree.
ℹ️
Context wraps a number of components with a value that all descendant components can access without going through properties at all.
Occasionally you find yourself passing properties through multiple components just to reach the place where you actually want to display it. (This is called prop drilling) This can become problematic in larger code bases. With Context you don’t have to do that…
You need 2 parts:
  • Provider - contains the value you want to access, set up via createContext(defaultValue) and then fill via <XYZContext.Provider value={value}>
  • Consumer - in each component that wants to use the value
Example:
Note how we use state to set the name and how that basically re-renders the entire site whenever we change it. To prevent that from happening with Memoization. We wrap some things in memo() and we’re good: const Header = memo(Header() { ... } );
⚠️
When you consume a context, you will get the value provided by the nearest provider going up the document. If no provider exists above the consumer, you will get the default value as defined when the context we created.
Ok, so a context can hold different values in different places. Sounds like a bug, but if you’re adventurous you can use it as a feature:
Example with context having different values in different places (borderWidth)
💡
You can put complex objects and even functions into context!
The problem with this is that everything consuming anything from inside the context will update if something updates in there, even if it’s something that your Component doesn’t even use. (will be addressed in future version of React or can be done via context-selector now)
Example with context as a delivery mechanism for stateful value and setters
Switch between dark and light mode
notion imagenotion image

useTransition

New in React 18: Concurrency concept. useTransition can be used to tell React that certain state updates have lower priority. When calling useTransition you get back an array with two elements: an isPending boolean value (tells you if the update is still pending) and a startTransition() function that can be wrapped around a state update to tell React that it is a low priority update.
Note how setFilterTerm() is wrapped by startTransition() - without the use of useTransition() the app could get unresponsive.

useDeferredValue

If you can’t use useTransition() because the code that should be wrapped is outside your control, you can use useDeferredValue(). You don’t wrap the state-updating code, instead you wrap the value that’s in the end generated or changed because of the state update.
React will perform other state or UI updates with a higher priority than updates related to the products value.

useReducer

ℹ️
The term reducer is used to refer to the function or a set of functions that converts the current state into a new state based on a given action. In React we expect reducers to be pure, deterministic and side-effect free as well.
💡
You invoke dispatch with an action object, that is then passed to the reducer along with the old state, and the reducer is expected to return the new state.
Flow of data is similar to a useState hook
  • starts with an initial value
  • then updates as the application progresses
BUT the way that you update the internal state is more complex, in that you "reduce" the new state from the old one using functions and actions.
notion imagenotion image
dispatch works as our enhanced setter function, which allows us to not set the value directly, but rather instruct the reducer function on how to set the value.
👉🏼
Alternative to useReducer: The external library use-reduction provides a much cleaner interface, namely useReduction

Effects

ℹ️
Effects are functions that run inside a component under certain circumstances. This can be done with an effect hook called useEffect
An effect in a useEffect hook is triggered when either value in a set of dependencies changes.
An effect can define a cleanup function that runs either before the effect is triggered again or if the component unmounts.
As you see above, every effect may return a function that cleans up after it. This lets us keep the logic for adding and removing subscriptions close to each other. They’re part of the same effect!
But it doesn’t have to do cleanup. Here’s an example without:
We can also do just the cleanup
We can pass in a second argument to useEffect that allows us to restrict when the effect runs. If we give it a variable it will only run the effect if that variable updates!

LayoutEffect

If we use useLayoutEffect instead of useEffect we can run an effect after React generates the HTML, but before the browser updates the UI and displays it. (Only needed in special cases)
notion imagenotion image

Dependency Arrays

Used by useEffect, useCallback, useMemo and useLayoutEffect.
3 ways - very different outcomes! Note how a missing dependency array does pretty much the opposite of an empty dependency array!
  • don’t specify an array at all - hook should be triggered on every render
  • specify an empty array - hook will only trigger on mount and never again
  • specify a non-empty array - hook will trigger if any of the given values in the array change on a render

Events

Events are the way users interact with a JavaScript web application.
To handle an event, assign any function to the value of the event on an object that might dispatch such an event. The event handler function will be called with a single argument: an event object (you can ignore it if you don’t care)
Another example:
You can only use React to listen for events that are actually supported by React.

Supported Events

Clipboard events - onCopy, onCut, onPaste
Composition events - onCompositionEnd, onCompositionStart, onCompositionUpdate
Keyboard events - onKeyDown, onKeyPress, onKeyUp
Focus events - onFocus, onBlur
Form events - onChange, onInput, onInvalid, onReset, onSubmit
Generic events - onError, onLoad
Mouse events - onClick, onContextMenu, onDoubleClick, onDrag, onDragEnd, onDragEnter, onDragExit, onDragLeave, onDragOver, onDragStart, onDrop, onMouseDown, onMouseEnter, onMouseLeave, onMouseMove, onMouseOut, onMouseOver, onMouseUp
Pointer events - onPointerDown, onPointerMove, onPointerUp, onPointerCancel, onGotPointerCapture, onLostPointerCapture, onPointerEnter, onPointerLeave, onPointerOver, onPointerOut
Selection events - onSelect
Touch events - onTouchCancel, onTouchEnd, onTouchMove, onTouchStart
UI events - onScroll
Wheel events - onWheel
Media events - onAbort, onCanPlay, onCanPlayThrough, onDurationChange, onEmptied, onEncrypted, onEnded, onError, onLoadedData, onLoadedMetadata, onLoadStart, onPause, onPlay, onPlaying, onProgress, onRateChange, onSeeked, onStalled, onSuspend, onTimeUpdate, onVolumeChange, onWaiting
Image events - onLoad, onError
Animation events - onAnimationStart, onAnimationEnd, onAnimationIteration
Transition events - onTransitionEnd
Other events - onToggle
 

Custom Hooks

ℹ️
The definition of a custom hook, is a function that uses a hook. Simple as that.
For example:
Than use like this:
Another example that handles form input
then use like this:
Get more hooks here:

Forms

ℹ️
Controlled inputs - React manages what’s in each input via value and onChange Uncontrolled inputs - React doesn’t care about anything and you only look at the input once the user submits. Then you access the inputs via evt.target.elements.* in the onSubmit event.
This is how you handle controlled inputs:
We specify both the value and the onChange properties for our inputs. This is required to make a controlled input.
If you set the value directly in React, you must also listen for the change event and update the value and this makes your input controlled.
You can use this to filter input:
or to apply a mask:
Uncontrolled Inputs:
Example: Controlled via Uncontrolled Submit via POST
With controlled inputs:
Same thing with uncontrolled inputs: (actually simpler in this case!)

File Inputs

File Inputs can only be uncontrolled.
 
Next.js example (Move?)

Optimising performance - useMemo

Minimize re-rendering! JavaScript tries to run at about 60 fps (16ms per frame) Each time React renders one or more components it counts as one frame. If the entire React render takes more than 16ms, your browser will start to treat your script as “slow” and start dropping frames. If you have lots of animations, your users will notice…
Response time matters - if a user interface doesn’t update within 0.1 seconds, it does not seem instantaneous to the user. We’re already losing 16ms because due to the new state of component rendering only on the next frame, let’s not waste the rest of the time we have…
Memoization is the concept of remembering the last input and output of a pure function. If the function is invoked again with those same inputs, we just return the same value again rather than call the function again. - This only makes sense for pure functions whose return value depends solely on their inputs! Similar to caching, but usually only remembers the last value.
This is a shitty example that doesn’t work. Figure this out later…
You can memoize bits of React applications in three ways:
  • memoize an entire component
  • memoize a bit of JSX
  • memoize a property to be passed to a component
Memoize a component:
use useMemo to mamoize any value between renders
useCallback is basically the same as `const useCallback = (fn, deps) => useMemo(() => fn, deps);
notion imagenotion image

React Developer Tools Browser Plugin

Adds a few things to the Inspect panel. (Which you should already be using for the console, etc.)
notion imagenotion image
notion imagenotion image
Components lets you inspect react components!
Profiler shows you how long everything takes, etc.
And this setting is also convenient: highlights each component that re-renders:
 
notion imagenotion image

Common Errors

Changing uncontrolled input to be controlled

Warning: A component is changing an uncontrolled input to be controlled. This is likely caused by the value changing from undefined to a defined value, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info: https://reactjs.org/link/controlled-components
Happens in this case:
Not obvious, but starting the state out as undefined is the issue. Do this instead:

Other stuff

props.children gives you all the child-elements
Custom elements won’t take on className automatically (<Card className=’blah’> does nothing), you’ll have to apply it yourself (props.className) in the component
 
function Card(props) {} is the same as const Card = (props) => {}
 
 
 
 

Leave a comment