Started on: 22-11-2023
Finished on: 08-12-2023
Codevolution:
Official Docs: https://react.dev
What and Why? Create new app using Vite & Folder structure
Component-driven architecture
Functional components & export (default and Named { ... }
)
Component Lifecycle - Mounting, Updating, Unmounting, Error Handling. Diff methods are called as and when the component goes through stages above
JSX (evaluate JS within curly-braces, single-element return, fragment <>
, optionally warp with parentheses return (<> </>);
for increased readability and avoiding errors after JS Automatic-semicolon-insertion, camelCase attributes, double-curlies {{ ... }}
to pass an object). Everytime state variable changes or new props values are recieved, the component function runs and JSX is returned again to provide dynamic content
Virtual DOM - copy of actual DOM, actual DOM changing is expensive so we change virtual DOM and at the end match with actual DOM and change only what is mismatch, not whole
Important Learning - whatever executable is placed in the root of a component (inside function) is run every time the component re-renders and it returns JSX every time, useEffect
hook and Live Search uses this phenomena.
Also, whenever a parent re-renders, all its children do too even when they have no updated data sent to them, use memo() to avoid this wastage of resources.
props (immutable, Hello({ msg })
, props
variable, props.children
, default value), name must match in call and definition when not using props
variable since its not a JS method call but a React construct
state - state variable and setter function, variable is immutable, pass either a value to set in the setter or pass a function reference (using arrow function) containing logic to execute, takes in its own state variable’s current value as argument. Ex - setTodos(currentTodos => { // add todo and return new array })
put this in the button onClick handler method and not root (it will run setter and render entire component in a loop otherwise)
Hooks - pre-defined methods that always start with “use
” prefix, always called at component function root not inside loops or if-else
Event Handling - (handler function w/o args, pass args to handler function using arrow function, event
variable)
Child-Parent data passing - send method reference as prop to call parent’s method, can pass args too - obviously we need to use arrow functions for that
Important learning - to pass a function with arguments we NEED to use arrow function (e.g. state setter, event handler with args, child-to-parent function reference prop with args). i.e. when we need to store functions for later calling but with args, otherwise we can just specify function by name. Ex - { clickHandler }
vs { () => clickHandler('Hi') }
Conditional rendering - if
, ternary operator ?:
, short-circuit (&&
)
Rendering lists: { names.map((name) => <h2>{name}</h2>) }
where const names = ['Abhi', 'Arya']
. Use a unique key
attribute for better React DOM building.
Styling - .css
stylesheet, inline using JS objects, Module stylesheet (myStyles.modules.css
), CSS in JS Library
Forms - use a state and onChange
to receive input, handler function for onSubmit
and prevent page refresh mechanism
HTTP GET and POST - fetch()
method or a thirdy-party library like Axios, useEffect
hook for GET and a onSubmit handler function for POST
useEffect hook - customize side-effects, placed at component root useEffect(()=>{}, [a,b,c])
runs function every time there is change to any of the states a
, b
or c
. With empty []
as second parameter it calls arrow function only on the first load of the component (this is how we send GET)
Important learning - spread syntax ...arr
means that we are unwrapping elements of the array. Ex - [...arr, 2, 3]
is a new array, {...obj, name}
is a new Object . Ex - used to add element to immutable array state variable and return it, add completed property to todo object and return it in the ToDo app.
localStorage - use in useEffect
, stores KV pairs localStorage.setItem("ITEM", jsonStr)
and get with localStorage.getItem("ITEM")
Live search: using re-render to run stuff placed in root of the component function, filteredList
is built everytime query
changes state, query
comes from form input of course
useTransition: mark state updates and transitions using this hook, and display a message, execute logic, etc… when state change happens
useContext : pass data directly to any grandchild component skipping any children using Context API (global state mamangement), we can send props with context tag too (including callback function refs)
useReducer : replcement for useState
but better, similar to reduce in Java and JS
const [currState, dispatch] = useReducer(reducer, initState)
function reducer(currState, action) { }
// use dispatch() to call reducer later onClick
memo: wrap a functional component inside export const newComponent = React.memo(myComponent)
and it returns a newComponent
that has in-built memoization and does not re-renders when it doesn’t need to (no change in its state or props) when its parent does
useMemo: const isEven = useMemo(()=>{ //code }, [a])
stores results of all code execution and runs (and re-render) only when a
is changed to an unseen before value, otherwise stored value is returned if there is no new a
or we’re re-rendering because of some other state variable change, a
is one of the inputs to the function
When a component re-renders, all the arrow function variables placed in the component function root get reinitialized, their body contents may remain the same but React sees them as a diff ones. If they’re passed as a prop to a component, that component will re-render unnecessarily. It will even fool React.memo()
wrapped child component since React believes prop value has legit changed.
useCallback: const cachedFn = useCallback(()=>{ //fn }, [a])
similar to useMemo but returns a function ref which changes only if value of a
has changed between re-renders, a
is one of the inputs to the function, we use cachedFn
as callback prop wherever fn
was used
Difference? useMemo calls the function and caches its return values and returns one of those values, whereas useCallback caches the function itself and returns a function reference
useRef - const myRef = useRef(init)
, a ref’s current
field can be used as a variable holding values but they do not re-render component upon change. Read/write value to it using myRef.current = newVal
. If we put this itself or any value displayed on screen in a ref (like prop or state) it will not reflect in browser so be careful.
We can also store DOM elements in a ref, const myRef = useRef(null)
and attribute on a JSX element use ref attribute <input ref = {myRef} />
, when components renders for the first time myRef
will point to the <input>
tag and we can do stuff like myRef.current.focus()
or myRef.current.play()
, myRef.current.pause()
etc.
Error Boundaries - upon error don’t remove UI element instead display fallback UI, error boundary is a special component that wraps code prone to error, ErrorBoundary
is a custom “foobar” class component that we wrote with overridden lifecycle methods
<ErrorBoundary fallback={ <p>Something went wrong</p> }>
<Profile />
</ErrorBoundary>
Portals - render components outside root DOM element, by default everything is rendered as child of App
component placed in <div id="root">
element of the DOM (index.html
). If we want to render any HTML code in another HTML tag other than “root”. We can do so using Portals.
{createPortal(children, domNode)}
// in component JSX
{ createPortal(<p>Test</p>, document.getElementById("overlays")) }
// in index.html
<div id="overlays"></div>
The code will directly be injected in the “overlays” tag, and will act as children of whatever component its called from, meaning we can pass props, state etc. as we would to a normal child, Ex - used to create Modal popups
Custom Hooks - put common logic to components in a normal JS function defined in its own file and named useXXXX
so that linters etc. recognize it as a custom hook
React Server Components - SSR, render JS not in the user browser but on the server, some areas on the page instantly load, we can also access data layer right from inside a server component so no need of APIs. React Frameworks like Next.js and Remix use them internally.
Explore Ecosystem - Axios, React Router, Redux Toolkit
Class Components & Legacy most used topics