Front-end tool to render interactive web user interfaces.
Declarative immutable views.
Component-based: embed HTML-like markup within JavaScript using JSX XML-like syntax (violates separation of concerns).
From Facebook.
Note that updated docs on are on react.dev. Watch out for legacy docs.
Hello World react app. Code in hello.html.
<h1>Hello, world!</h1>
is an example of JSX embedded within
JavaScript.
text/babel
mime-type used to specify use of Babel, which
allows supporting newer JavaScript features in browsers
using syntax transformers. Used for translating embedded JSX.
Example uses a self-contained HTML file which translates at runtime. Not recommended for production.
Modern JavaScript development for the browser typically uses a build step on the server to build the artifacts deployed in the browser.
Examples are npm or yarn (yarn is from Facebook; better reproducibility and performance than npm).
Allows writing modular code with module inclusion directives
like require
. Bundle everything together to minimize
HTTP requests. Examples: webpack,
browserify and
parceljs.
Allows writing code in more modern (or alternate) dialects of JavaScript and have it compiled to dialect supported by browser. Examples: babel, typescript (from MS, used in angular), dart (from Google, in ng2), Elm.
const element = <h1>hello world</h1>;
<h1>...</h1>
represents JSX, an extension to JavaScript syntax.
It is not a JavaScript string; it is not HTML.
JSX is syntactically a JavaScript expression.
A single JSX expression can be written over multiple lines; recommend wrapping in parentheses to avoid automatic semicolon insertion pitfalls.
Can embed JavaScript within braces inside JSX: const msg =
<h2>hello {user.firstName}</h2>
.
JSX elements can have props
properties (look similar to HTML
attributes, but can also have non-string-values like Object
or Function
):
const msg = <h2>hello {user.firstName} <img src={user.avatarUrl}/> </h2>
Welcome. Code in welcome.html.
Can define JSX components using a JavaScript function which
takes a single argument props
object representing the properties
the component is called with.
Properties are immutable during the lifetime of a component.
User-defined component names must start with upper-case character.
We are rendering a list of JSX elements.
Each JSX element in a list must have a key
attribute which
makes it easy for react to identify it.
Since React JSX attempts to look like HTML, but is actually merely syntactic sugar for JavaScript code, it is necessary to replace HTML identifiers which are identical to JavaScript reserved words:
Instead of the HTML class
attribute, use the JSX/DOM
className prop.
Instead of the HTML for
attribute, use the JSX/DOM
htmlFor prop.
See Props for more information about the props available for built-in components
Static Course Schedule Display Code in schedule1.html.
Top-level <App schedule>
component which renders a <Schedule
schedule>
component.
<Schedule schedule>
component renders a table with a heading and
rows of <CourseSchedule>
components.
A <CourseSchedule schedule>
renders a single course schedule
row.
Static Course Schedule + Form. Code in schedule2.html.
Top-level <App schedule>
component now renders a <SearchableSchedule
schedule>
component instead.
<SearchableSchedule schedule>
component renders a <SearchForm>
component followed by a <Schedule>
component.
<SearchForm schedule>
component renders a select control for selecting
a dept
department and an input control to allow filtering by
descr
course description. The select control is pre-populated
with All
plus all unique dept
in schedule
.
<Schedule schedule>
component is as in previous slide.
Static Filtered Schedule Code in schedule3.html.
No change in example rendering, but <Schedule schedule dept
descr>
now allows filtering schedules based on added dept
and
descr
props
.
Schedule with Form Values Initialized. Code in schedule4.html.
Added value
prop to <select>
and <input>
widgets.
Cannot change <input>
widget.
Note warning from react in console.
Fully Working Dynamic Schedule. Code in schedule5.html.
Added dept
and descr
state to <SearchableSchedule>
component.
Pass value of dept
and descr
as props to both
<SearchForm>
and <Schedule>
components.
Pass state change handlers deptChange
and descChange
down to <SearchForm>
component.
The <SearchForm>
component renders both the
<select>
and <input>
widgets with a onChange
handler which calls the change handler props with
the target value.
A react component is not the same as a DOM element; the react component wraps the DOM element.
A react event is not the same as a DOM event; the react event wraps the DOM event.
With the react hooks API, all react components can be implemented using functions.
Note: before hooks were added to the react API, stateful react components were implemented using JS classes, but such code is now regarded as legacy and will not be covered in this course.
The function for a component is called each time the component is rendered.
A component is rendered when first mounted in the DOM and re-rendered when any of its props or state constituents change.
The function implementing a component is simply a function with a Pascal-cased (AKA upper-camel-cased) name which takes a single props parameter and returns a rendering (usually JSX, but can also be a string or array of JSX) of the component.
The function implementing a component can access and update the
state of a stateful component using the useState()
hook.
The function can respond to side-effects using the
useEffect()
hook.
Other hooks include useContext()
, useReducer()
,
useCallback()
, useMemo()
and useRef()
.
It is also possible to have user-defined hooks.
The hook is called
with either an initial state value initValue
or a function
initFn
which should return the initial state value when called.
useState(initValue) useState(initFn)
Returns a pair [value, setValue]
where value
is the current value of the state constituent and
setValue()
is a function for updating the constituent.
The initial value initValue
is used for initializing the state
before the first render of the component; it is ignored for
subsequent renders. Hence if initValue
is expensive to
compute, the computation can be done lazily by using
the useState(initFn)
form; initFn()
will be called only
before the first render.
The state can be updated using the second element setValue()
of the return value.
Updating the state will re-render the component; without care, this could result in an infinite loop.
Counter. Code in counter.html.
Initial render will set count
to 0.
Clicking on +
or -
button will setCount(count + 1)
or
setCount(count - 1)
.
The setCount()
call results in the component's state changing.
The state change results in a re-render.
In the re-render, the useState()
call returns the current
value of count
.
Update counter after a delay in Bad Async Counter. Code in bad-async-counter.html.
Each render gets its own copy of event handlers.
Each event handler captures its current environment in a closure.
Closure captures environment when function is defined, not when it is executed.
Counter is not updated until the timeout expires.
But update()
handler captures count
value at time the
counter was last rendered.
Result is a sequence of multiple clicks between timeouts reduced to a single click.
Fix by using a functional argument to setCount()
in
Fixed Async Counter
(code: fixed-async-counter.html).
Function argument is current value of
count
within state.
Display alert containing counter value after a delay in Alert Counter. Code in alert-counter.html.
Because doAlert()
captures its environment at the time
it is defined, the alert()
shows the count
at the time
when the Show Delayed Alert
button is clicked, not the
value at the time the alert()
is displayed.
Problem occurs because the doAlert()
is using a
stale closure.
Component props are like immutable function arguments.
Component state is like the component's memory. It keeps track of the dynamic state of the component.
Keep a logical state constituent in only one place, usually in a common parent of all components which set/use it.
If state can be derived from props, then it is not state. (if the computation is expensive, then it can be cached using the useMemo() hook).
The useEffect()
hook can be used to run an Effect
after a render:
useEffect(fn, depArray)
If useEffect()
is called without depArray
, then react will
call function fn()
after every render.
If depArray
is empty, then fn()
is called only after first
render (similar to legacy componentDidMount()
lifecycle handler
for class-based components).
If depArray
is specified as an array of values, then fn()
is
called only if some value in depArray
is different from its
value in the previous render.
If fn()
returns a function, then that function is called before
each subsequent render and when the component is unmounted.
The returned function can specify cleanup.
useEffect()
can be used to perform asynchronous tasks like
fetching data, setting up a subscription, etc.
Use an effect to set an interval timer which updates count state every second.
Broken Clock (code in broken-clock.html): new interval timer created for every render!!
Still Broken Clock (code in
still-broken-clock.html):
Use [] dependency array to create interval timer only after first
render. However, stale closure means that count
only updates
from 0 to 1.
Fixed Clock (code in
fixed-clock.html): avoid stale
closure problem by using function argument to setCount()
.
Remove clock from DOM when button clicked: Broken Unmount Clock (code in broken-unmount-clock.html).
Interval timer continues to run after clock removed from DOM and attempts to update state.
Fix in Fixed Unmount Clock
(code in
fixed-unmount-clock.html) by returning a clean-up handler from
useEffect()
function.
Single source of truth. Do not maintain state of component
in DOM as well as in react. Typically for managed components,
DOM state is reflected immediately into react state using
a onChange()
handler.
Migrate state to common ancestor component. Pass down change handlers to component which will change the state.
Asynchronous initialization should be done using useEffect()
.
Prefer composition over inheritance; i.e., do not make
DangerButton
a subclass of Button
; instead have it
contain a Button
component.
Only call hooks from the top-level of React function components or from the top-level of custom hooks.
Do not call hooks from inside loops, conditions or nested functions.
Do not call from regular JavaScript functions.
Implementation depends on hooks always being called in the exact same order.
These rules follow from the fact that React identifies hooks based on their static order within a function component.
Custom hooks can be used to encapsulate some code.
Custom hooks must have names starting with use
followed by an upper case letter.
Custom hooks can call other hooks, but must follow the Rules of Hooks.
Multiple Select and Add/Delete components.
Code uses a custom
hook to factor out the commonality between citiesUpdate()
and
selUpdate()
in multi-cities.html.
Multiple Select and Add/Remove Components using Effects; code
Uses effect to resolve earlier bug.
Uses a custom hook containing an effect to log component lifecycle events.
A common problem with functional programming is that a function deep in the call tree needs access to a particular piece of data. Consequently, all intermediate functions will need to pass in that data even though they have no interest in that data.
React has a similar problems with props, referred to as prop drilling.
Using react Contexts provide a solution.
Contexts allow a nested component to access data from an enclosing component without needing to drill the data through intervening components using props. That is, we can avoid props drilling.
Create a context using createContext(defaultValue).
const ColorCtx = React.createContext('cyan');
Specify the context as the context provider when rendering a subtree.
<ColorCtx.Provider value={color}> ... </ColorCtx.Provider>
Access the context in the consumer component:
const value = React.useContext(ColorCtx); //use value in component
The value will be that set by the enclosing context provider (if any).
If there is no enclosing context provider, then it will be
the defaultValue
specified when creating the context.
Pass color via context.
Example illustrates the use of React's special children prop.
A Ref
is a wrapper object which contains a mutable current
field.
This can be used to track mutable state across renders. Unlike
component state, changes to the ref state does not cause a re-render.
A React component is not an HTML element. It is possible to get a reference to the underlying element using useRef().
Canvas Example with code in canvas.html.
Use a Ref
variable with initial value init
using
useRef(init)
.
const canvasRef = React.useRef(null);
Initialize the Ref
variable by referring to it using
a ref
prop when rendering the component.
//set canvasRef.current to refer to //<canvas> DOM element <canvas ref={canvasRef}...>...</canvas>
Use the .current
property to access the actual element:
const ctx = canvasRef.current.getContext('2d');
React Hooks Clocked Counter.
Run using npm install
followed by npm start
; then
point browser to http://localhost:2346/entry.html
.
Sources:
An element is a plain object providing an immutable description of
"a component instance or DOM node and its desired properties".
An element is not an instance. Instances are described by elements. React takes care of creating, updating and destroying instances.
JSX is merely syntactic sugar for React.createElement().
Element merely contains a type
which is a String
, Function
or subclass of a React.Component
or a react
Fragment,
props
which is an Object
and Children
which is a list of
elements.
Sebastian Weber, The last guide to the useEffect Hook you’ll ever need, Nov 2020.
developerway. Deep React articles.