I am thankful to be able to attend a React training workshop organised by my company. I have been using React in my job but this workshop made me realise I still have lots to learn.
The exercises were very manageable. I learnt the most from the instructor’s detailed explanation of how React works:
- Babel is not part of React but it was helpful to know how Babel makes our lives easier by parsing JSX. I found a Stack Overflow thread which describes the relationship between these technologies.
- I learnt that Babel evaluates
<div>
to a string due to the first letter being a lower-case letter. On the other hand, when we callReact.createElement
with<App/>
as an argument, Babel will pass the reference to<App/>
intoReact.createElement
sinceApp
begins with an upper-case letter.
- I learnt that Babel evaluates
- I took JSX for granted and thought it was part of React. Other UI libraries use JSX too.
- I learnt that JSX is syntax sugar for nested function calls. For example:
React.createElement('someDiv', null, React.createElement(...))
. If not for JSX, we would need to have several of such nested function calls to build composable UI. - Some JSX attributes are metadata for React and do not go into the HTML code. For example,
onClick
.
- I learnt that JSX is syntax sugar for nested function calls. For example:
- In OOP, classes are blueprints and objects are instantiated from classes. In React, components are blueprints and elements are “instances” of components. In this article, there are distinctions between React Components, Elements, and Instances.
- There is a difference between:
<Button icon={<FaTrash/>}>
(i.e. passing in an element) and<Button icon={FaTrash}>
(i.e. passing in a component)
- Depending on the implementation of
Button
, we can refer to the icon as{icon}
or<Icon/>
. To makeicon
becomeIcon
, use named destructuring ofprops
. - Passing in components may not be ideal since we do not want to pass its config in as props.
<Button icon={...} iconColor={...}>
contains props applied to components of varying levels of abstraction. It is untidy and we would not have known ifButton
expects us to configureicon
outside or inside ofButton
.
- There is a difference between:
- Each child in a list should have a unique
key
prop.- I always see this in my console but I did not bother to figure out why. And I did the one thing which the instructor advised against - setting
key
to be the index of the element in the list. - The
key
prop allows React to run a diff on virtual DOMs. - When we remove an element in the middle of the list, the indices of the elements are no longer constant. This reduces the performance of the diff function.
- Random numbers as
key
are not ideal either. Each re-render regenerates the random numbers and these numbers have a small chance of collision. - As such, React prefers keys in this order: Good keys, no keys, bad keys.
- I always see this in my console but I did not bother to figure out why. And I did the one thing which the instructor advised against - setting
- In React, we need to trigger a state change through an event before the DOM gets updated by React.
- For instance, by clicking on a button like this
<Button onClick={() => setMyState(...)}>
. const [myState, setMyState] = useState({key1: 'val1', key2: 'val2'});
- If we want to use a collection of data (arrays or objects) as the state, do:
setMyState({...myState, yourAffectedKey: newVal})
. - We do this because the component gets regenerated along with the brand new state constants when we call
setMyState
.
- If we want to use a collection of data (arrays or objects) as the state, do:
- For instance, by clicking on a button like this
- We should memoise slow functions with
useMemo
so that we do not rerun it upon re-render.- From the docs, the hook accepts a dependency array as its second parameter. The function is re-computed if anything in the dependency array changes.
- A dependency array is an array which contains variables whose values may change.
- From the docs, the hook accepts a dependency array as its second parameter. The function is re-computed if anything in the dependency array changes.
- Hooks are how functional components tap into React’s API.
- There is only one re-render per event loop.
- If we run multiple
setMyState
in a function, there will only be 1 re-render.- This means that subsequent statements in the same function should not expect to retrieve the latest state.
- If we run multiple
- React hooks must be called in the same order in every component re-render.
- As such, we cannot put hooks inside conditionals.
- React does not have two-way binding or observables. It works with immutability.
- To share state between siblings, lift state to the nearest common ancestor.
- To pass information down through several nodes, consider
useContext
over prop-drilling.ContextProvider
can provide information to consumers far down the tree.
- Controlled vs uncontrolled
<input type="type">
= uncontrolled<input type="type" value="">
= controlled but needs anonChange
handler<input type="type" onChange="">
= uncontrolled
e.target.value
is always a string
useRef
allows users to reference the DOM and not cause unintended changes elsewhere
- The React router matches routes by specificity and not by order.
- There is no standard for defining query parameters for array of values e.g.
?list=1,2,3
or?list=1&list=2&list=3
and so on.
- There is no standard for defining query parameters for array of values e.g.
- React.lazy
lazy(() => import('./SomeComponent'));
returns an object which could become a component but is not a component yet.- Supported by React.suspense
- If something is not loaded yet, we render the
fallback
. - This can help bring down the bundle size.
- If something is not loaded yet, we render the
- [XHR vs Ajax vs FetchAPI vs Axios](XMLHttpRequest, Ajax, FetchAPI, and Axios)
- Side effects should go into
useEffect
.- List of side effects:
- Network
- Local storage
- Cookies
window
document
- Working on DOM via
refs
- List of side effects: