React Cheatsheet (Q&A — Concepts You Need to Know to Pass Tech Interview)

Hanwen Zhang
17 min readOct 30, 2022

--

Share some coding notes I took in the past which helped me understand the concepts, and these are questions you may be asked during interviews.

Photo by Lautaro Andreani on Unsplash

React

What is React?

  • A User Interface Library (for building user interfaces)
  • Component Architecture (different functions control different parts of UI)
  • Data Flow in React (top to bottom one-way data flow, component to children)
  • Component State (manage its own state and pass down to children)
  • Rendering + updating user interfaces, handling user input

What is the Component?

  • React is a component-based language
  • React allows you to compose complex UIs from small and independent pieces of code called “components”.
  • Components are like functions that return HTML elements that tell what should be rendered on the screen (via a render() function).
  • Components are core UI building blocks, reusable, you can use the component across different pages, and components are independent.

In React, everything is a component.

  • React as UI (user interface) library depends on components as an independent and reusable chunk of code that you can use anywhere in your application.

What is JSX?

  • JSX stands for JavaScript XML, it allows us to write HTML in React, and it comes with the full power of JavaScript.
  • JSX makes it easier to write and add HTML in React and easily creates user interfaces for your web applications.
  • Old browsers are not compatible with JSX and React uses babel to transpile the code into older JS syntax to work with the browser

What is Virtual DOM?

  • The DOM is a tree of nodes that is constructed by the browser after parsing the HTML during the critical rendering path process. React takes a copy of this DOM and saves it in the memory => virtual DOM.
  • When you make any changes or trigger any action that will eventually update the view, React makes a new copy of the virtual DOM and apply the updates to the new copy
  • React will make a comparison using the diffing algorithm between the trees and will find the differences and batch the updates to the real DOM, in simple words, replace the old nodes with the new nodes.

How is Virtual DOM updated?

  • When you change something, the virtual DOM gets compared to the real DOM before any updates on the page.
  • React will figure out which objects have changed.
  • Only the changed objects get updated on the real DOM.
  • Changes on the real DOM cause the screen to change.
  • When you try to update the DOM in React, The entire virtual DOM gets updated.

Virtual DOM Benefit

  • It doesn’t re-render the entire DOM, only the changed nodes
  • It doesn’t cause a performance drop
  • Updating the virtual DOM is comparatively faster than updating the actual DOM (Real DOM manipulation is very expensive)

Pros of React

  • Easy to learn -> Strong community supporting
  • Component-based framework -> Reusability
  • VirtualDOM -> avoid unnecessary re-rendering, Real DOM manipulation is very expensive
  • Diff Algorithms (outputs the set of differences between two inputs) -> reconciliation (“virtual” representation of a UI is kept in memory and synced with the “real” DOM by a library such as ReactDOM)
  • JSX (HTML + JS) -> write HTML inside of JavaScript, good for dev — efficient context switching is now avoid
  • Focus on the view -> User Interfaces
  • hooks and component lifecycle -> allows us to control how our component should behave during its lifetime using various hooks.

What Problems does React Solve?

  • better handling of dynamic data for faster response times
  • and response to data changes instantly
  • renders the right components for a smooth user experience.

render()

  • it renders the HTML elements that the component contains into the DOM.

state

  • state is an object that contains data that lives inside of the current component as local or instance variables.
  • state is data that you can change inside of a component to then force this component to be re-evaluated
  • it is an object internally captured by a class (in the constructor, this.state)
  • an object that controls the behavior of the component, may change over the lifetime of the component.

state purpose

  • It is used to render data to the DOM
  • It is used to be passed down as props to a child component
  • It is used to be integrated with a method or a function

props

  • props are data you pass from a parent component to a child component
  • props down, the parent talks to the child
  • Can the child talks back to the parent using props too? NO -> using callback

super(props)

  • constructor(props) -> initialize an object’s state in a class, called before it is mounted
  • super(props) -> call the parent class constructor() of React component as a reference

Lifting State Up

  • For sub-components to talk to each other through parents
  • sharing state is accomplished by moving the local state up to the closest common ancestor of the components that need it.
  • by lifting the state up, we make the state of the parent component a single source of truth and pass the data down to sub-components

Lifting State Up vs Composition vs Inheritance

  • Lifting State Up: enable children components to have better smooth communication among each other
  • Composition: {props.children} — pass down as property children, contains any child elements defined within the component
  • Inheritance: not a good model to use in React

What are the side effects?

  • Side effects are basically anything that affects something outside of the scope of the current function that is being executed.
  • Example: API requests to our backend service.

How do you sync effects in a React component to changes in certain states or props?

  • first, we store the states/props into the parent component, i.e in which component where we trigger the onClick event; then to pass the state into another component, we simply pass it as a prop.
  • useEffect is called after React already commits the updates, i.e. the updates would be reflected in DOM; then you’ll update the state which will update the DOM again. The second way causes a re-render, but there’s only one commit to the DOM.
useEffect(() => {
// Called on first render and every props.foo update
}, [props.foo])

Functional Component

  • A pure function is a function that doesn’t have any side effects, doesn’t change data outside of the function scope, and doesn’t depend on any external state but only the inputs given to it
  • will render the same output for the same input (states and props)

Stateful Component vs Stateless Component

  • stateful components are keeping track of changing data
  • stateless components always render the same thing, print out what is given to them via props

Element vs Components in React

  • React Element is like an HTML element, an immutable object that describes a DOM node, you can not apply any methods to it.
  • React Component is a function or class that accepts an input and returns a React element.

Lists and Keys

  • key helps React identify which items have changed (added/removed/re-ordered) in order to render
  • give a unique identifier to every element inside the array, a key is required.
  • the key is a unique item for iterating through sub-components, always add the key to the up level!
  • { this.state.numArr.map((num, index) => ( <Child key={index} num={num} /> ))}

Key not using indexes

  • not recommended using indexes for keys especially the order of items may change — bad design.
  • If the key is an index, reordering an item changes it.
  • The component state can get mixed up and may use the old key for a different component instance.
  • Also, iterating over the list when it is large causes poor performance.
  • [a:0, b:1, c:2] -> [d:0, a:1, b:2, c:3] - bad
  • [d:unique key, a:unique key, b:unique key] - good

Attributes

  • defaultChecked - sets whether the component is checked when it is first mounted in <input>
  • dangerouslySetInnerHTML - React way of a replacement for using innerHTML in the browser DOM, is risky because it’s easy to inadvertently expose your users to a cross-site scripting (XSS) attack - <div dangerouslySetInnerHTML={__html: description} />
  • className, onChange, htmlFor, selected, value, style, tabIndex, readOnly

createPortal()

  • render children into a DOM node, behaves like a normal React child, but also includes event bubbling because in the DOM tree
  • building modals, dialogs, hover cards, and tooltip. with portals, you can render a parallel react tree onto another DOM node when needed.
  • ReactDOM.createPortal(child {any renderable React child}, container {a DOM element})

SyntheticEvent

  • entire wrapper over the DOM event system can be a lot of weights into React code base not using browser's addEventListener for event handling internally
  • because we run React in different environments, so we want consistency across multiple browsers like a wrapper
  • consistency -> wrapper(basicEvent) => a cross-browser wrapper around the browser's native event

React.Fragment

  • looks cleaner, avoid too many <div>
  • <React.Fragment>...</React.Fragment>

Naming Convention

  • [Domain]|[Page/Context]|ComponentName|[Type]
  • The Domain: Which product owns this component?
  • The Page or Context: what is the parent component? which product subpart/page this component belongs to?
  • The Component: what does this component do? e.g. sidebar, shortlist, chat conversation
  • Component types: view, button, connect, input, upload

Rendering

Re-renders Situations

  • The parent component re-renders, which causes all of the parent’s children to try to re-render, even if the props from the parent haven’t changed.
  • The component calls this.setState(), which causes a state update and a re-render
  • The component calls this.forceUpdate(), which causes a re-render.
  • Component change? Re-render. Parent changed? Re-render. Section of props that don’t actually impact the view changed? Re-render.

What does setState do?

  • setState will trigger re-rendering, and update/modify local state correctly
  • when involve previous value, we should always use a callback function to properly handle it based on the current value
this.setState((prevState) => {     //passing in a callback function instead of setState directly
return { number: prevState.number + 1 };
})

Why do we need a callback?

  • useState and setState both are asynchronous.
  • They do not update the state immediately but have queues that are used to update the state object.
  • Use the callback function to setState to make it correctly rendered the previous value instead of just assigning the new object.
  • React will batch several setState together into a single update for performing the state change due to the performance of rendering of React components.

setState() behind the scene

  • setState are asynchronous and are batched for performance gains -> react fiber -> then render
  • fiber: reconciliation, diffing algorithms — outputs the set of differences between two inputs -> no new key no change on virtual DOM, improve web performance
  • Batching: React groups multiple state updates into a single re-render for better performance.
  • using setState to change a variable inside any function, instead of making a render at each setState, React collects all setStates and then executes them together.
  • no matter how many setState calls you make inside a React event handler or synchronous lifecycle method, it will be batched into a single update.

Material UI

  • A simple and customizable component library that allows us to import and use different components to create a user interface in our React application
  • Saves a significant amount of time since the developers do not need to write everything from scratch.

CSS Module

  • import styles from "./Button.module.css"; - import CSS modules, change the CSS file name as well
  • <button type={props.type} className={styles.button} onClick={props.onClick}>

Styled Components

  • a package that helps you to build components that have certain styles attached to them (CSS-in-JS)
import styled from "styled-components";
export const Button = styled.button`color: white;` //using tagged template literal

Controlled Component vs Uncontrolled Component

Controlled Component

  • Data is handled by a React component <-> the input’s value is always driven by the React state
  • State mutation has an associated handler function managing its own state, and passing the new values as props to the controlled component.
  • takes its current value through props, and the parent component “controls” it by handling callbacks like onChange.
  • recommend using controlled components to implement forms
  • a component that renders form elements and controls them by keeping the form data in the component’s state.
  • <ControlledComp value={this.props.fromParent} onChange={this.props.handleChange} />
const { useState } from 'react';function Controlled () {
const [email, setEmail] = useState();
const handleInput = (e) => setEmail(e.target.value);
return <input type="text" value={email} onChange={handleInput} />;
}

Uncontrolled Component

  • Data is handled by the DOM itself.
  • a bit more like traditional HTML, keeps the single source of truth in the DOM,
  • you query the DOM using a ref to find its current value when you need it.
  • Refs provide a way to access DOM nodes or React elements created in the render method.
import React, { Component } from 'react';
export class App2 extends Component {
constructor(props){
super(props);
this.handleChange = this.handleChange.bind(this);
this.input = React.createRef(); //access the input DOM node and extract its value
}
handleChange = (newText) => {
console.log(newText);
}
render() {
return (
<div className="App2">
<input type="text"
ref={this.input}
onChange={(event) => this.handleChange(event.target.value)}
/>
</div>
);
}
}

HOC

HOC -> High Order Component

  • HOC is a pattern where a function takes a component as an argument and returns a new component under a certain reusing component logic pattern
  • take in the original component, and add some decoration and modification, and props to make it a new component, add more contents
  • example: connect in React-Redux connect(a, b)(OriginalComp)

Why HOC?

  • use it for reusability to share common functionality between components
  • same pattern but only applies to the one when we need it, and simply remove it when we do not need it

HOC Example

import React from "react";
const UpdatedComponent = (OriginalComponent) => {
class NewComponent extends React.Component{
render() {
return <OriginalComponent name="inject props"/>
}
}
return NewComponent
}
export default UpdatedComponent;
import ContentContainer from "../HOC/ContentContainer";
const HOCCounter = UpdatedComponent(Counter);
export default HOCCounter;

Router

What is React Router?

  • A great way to build single-page applications because you prevent a page refresh every time a link is clicked.
  • With client-side rendering, the page doesn’t refresh as you navigate through the different links.
  • Multiple pages in a single page app, URL changes, visible content changes.

Traditional multi-page routing

  • HTML is requested & loaded; Page change = new request + response (Server-side Rendering).

Single page application

  • Only one initial HTML request & response, Page (URL) changes are then handled by client-side (React) code -> changes the visible content without fetching a new HTML file (Client-side Rendering).
  • The goal is that we are able to handle different paths on our page, and load (render) different components for the different paths.

Link vs Route

  • Link component is responsible for the transition from state to state (page to page)
  • Route component is responsible to act as a switch to display certain components based on route state.

useParams()

  • Returns an object of the params for the route rendered.
// route: /user/:userName
const params = useParams();
return <h1>{params.userName}</h1>

useRouteMatch();

  • attempts to match the current URL
let match = useRouteMatch();
<Link to={`${match.url}/components`}>Components</Link>
<Route path={`${match.path}/:topicId`}>

React Router Implementation

import React from "react";
import {
BrowserRouter as Router,
Switch,
Route,
Link,
} from "react-router-dom";
export default function App() {
return (
<Router>
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
</ul>
<Switch>
<Route path="/about">
<About />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
</div>
</Router>
);
}

Lifecycle

Class Component vs Functional Component

  • we use class component when the component has its own local state and lifecycle before React 16.8
  • now we can use react hooks to perform local state and lifecycle in functional component

Lifecycle Effects

  • Functions trigger the code when a component is created, updated, or removed from the page

Lifecycle (3 phases) — mounting, updating, unmounting

  • Mounting (constructor() & render()): initialize constructor -> assigns the initial this.state, and render components -> we have over the initial render in the DOM
  • componentDidmount (initial render) -> only after the initial render then we call componentDidMount
  • Update: when the component updates as a result of a changed state or changed props
  • componentDidUpdate (update) -> when we update, we need to change some state to trigger the re-render
  • Unmounting: when the component is being removed from the DOM
  • componentWillUnmount -> proper clean-up to prevent memory leak (remove eventListener, remove setTimeout)

useEffect()

  • takes two parameters, 1st is callback function, 2nd is dependencies array
  • the returned function will be called after the component is removed
  • we can do clean up in the returned function
function XXX () {
const [name, setName] = useState("");
useEffect(() => {
console.log("This is component did mount");

return () => {
console.log("This is component did unmount");
console.log("returned function will be called on componentWillUnmount, for clean up, uunmount first then updates");
}
}, []) //no dependencies here, so only the first render

useEffect(() => {
console.log("This is component did update");
}, [name]) //will be called whenever the dependency updates

return <p>This is render.</p>
}

React.PureComponent vs memo

  • Same functionality, both are for performance improvement, React.memo is a higher-order component — wrapper
  • With PureComponent or memo, it already contains the logic of shouldComponentUpdate — compares the props
  • To compare current props and previous props to make sure it cuts off unnecessary renders

Shallow Compare — React.memo()

  • React.memo() does a shallow comparison of props and objects of props.
  • In JavaScript, comparing objects shallowly will always return false even if they have the same values
  • If you want more control and to be in charge of that comparison, React.memo accepts a second argument, a comparison function.

Error Boundary

  • class component only, define either or both getDerivedStateFromError (render a fallback UI after an error is thrown) and componentDidCatch (log the error information) lifecycle methods
  • catch JS errors in their child component tree, log those errors and display a fall-back UI
  • no error boundaries on event handler, async codes, server-side rendering, errors thrown in itself than children

Error Boundary vs Try…Catch…

  • Try…catch deals with imperative code: how you do something, you can catch errors in your code.
  • Error Boundaries deal with declarative code: what you do, like if there is an error, you can trigger a fallback UI

Hooks

What is Hooks?

  • Hooks are functions that let you “hook into” React state and lifecycle features from function components.
  • Hooks don’t work inside class components. You can also create your own Hooks to reuse stateful behavior between different components.

useState()

  • const [state, setState] = useState(initialState) - value and setter function
const computationInit = () => return 0;function App() {
const [count, setCount] = useState(() => computationInit()); //callback function, only called at the initial time
const [name, setName] = useState(""); //another local state, initial state in ()
return (
<>
<button onClick={() => setCount(count + 1)}>+</button>
<div>Count Number {count}</div>
<button onClick={() => setName("Hello")}>show name</button>
<div>{name}</div>
</>
);
}
export default App;
function App() {
const [{ count1, count2 }, setCount] = useState({ count1: 1, count2: 2 });
return (
<>
<button
onClick={() =>
setCount((prevState) => { //without ...prevState, it overwrites the object
return {
...prevState, //...prevState first - give all the key I have then make modification to the count1
count1: prevState.count1 + 1 //we only modify count1 without changing/overriding count2
};
})
}
>
+
</button>
<div>Count 1 - {count1}</div>
<div>Count 2 - {count2}</div>
</>
);
}

useEffect()

  • create a side effect when something happens or dependencies change, “If some variable changes, do this”.
  • useEffect runs after DOM is parsed due to JS's asynchronous nature
  • useEffect(...,[]): componentDidMount() - called once component mounted (was evaluated and rendered)
  • useEffect(..., [someValue]): componentDidUpdate() - called once component updated (was evaluated and rendered)
  • useEffect(() => {return () => {...}}, []): componentWillUnmount() - called right before the component is unmounted (removed from DOM)
function XXX () {
const [name, setName] = useState("");

useEffect(() => {
console.log("This is component did mount");
return () => {
console.log("This is component did unmount")'
}
}, []) //empty array -> ComponentDidMount (no dependency, we call it after every render)
//with dependencies in the array, will be called when the value changes

useEffect(() => {
console.log("This is component did update");
})

return <p>This is render.</p>
}

useEffect() + Axios

  • In useEffect make a request if there is a network error or not and set a timeout to avoid the fetch time being infinite.
React.useEffect(() => {
(async () => {
try {
const result = await Axios.get(
"http://media.xiph.org/mango/tears_of_steel_1080p.webm",
{ timeout: 5000}
);
// Do something here
} catch (e) {
console.log("The link is not avaible", e.message);
// Do something here
}
})();
}, []);

useRef()

  • request the DOM using a ref to find its current value when you need it (use ref to reference elements inside of your HTML)
  • ref stores value persistent but do not cause your component to re-update when it is changed, whereas setState triggers re-render
  • when you need to change any value, still use setState()
const [name, setName] = useState('')
const inputRef = useRef()
const prevName = useRef('')
function focus(){
inputRef.current.focus() //inputRef.current refers to <input value>
}
if (name === inputRef.current.value) {
}
useEffect(() => {
prevName.current = name
}, [name])
return (
<>
<input ref={inputRef} value={name} onChange={e => setName(e.target.value)}/>
<div>My name is {name}, used to be {prevName.current}. </div>
<button onClick={focus}>Focus</button>
</>
)
}

useContext()

  • specify certain pieces of data that will be available to all components nested inside the context with no need to pass this data through each component
  • export const ThemeContext = React.createContext() initiate the context, default values, not actually in use but for auto-completion
  • const [darkTheme, setDarkTheme] = useState(true)
  • <ThemeContext.Provider value={darkTheme}>{everything has the access to the value props}</ThemeContext.Provider>
  • class: <ThemeContext.Consumer>{value is available to the component}</ThemeContext.Consumer>
  • function: const darkTheme = useContext(ThemeContext) - then darkTheme is available to use in the component

useReducer()

  • handling complex state interaction management, an alternative to useState
  • reducer takes 2 parameters, a function, and an initial value, and returns a single value
  • function reducer(state, action) { return {} } - usually, be switch cases with the action.type that dispatched to reducer for changes
  • const [state, dispatch] = useReducer(reducer, initialState) - initialState always objects like [] {count:0}
  • function increment() { dispatch({ type: "increment" }) } - dispatch the action type to the reducer
const ingredientReducer = (currentIngredients, action) => {
switch (action.type) {
case 'SET':
return action.ingredients;
case 'ADD':
return [...currentIngredients, action.ingredient];
case 'DELETE':
return currentIngredients.filter(ing => ing.id !== action.id);
default:
throw new Error('Should not get there!');
}
};
const httpReducer = (curHttpState, action) => {
switch (action.type) {
case 'SEND':
return { loading: true, error: null };
case 'RESPONSE':
return { ...curHttpState, loading: false };
case 'ERROR':
return { loading: false, error: action.errorMessage };
case 'CLEAR':
return { ...curHttpState, error: null };
default:
throw new Error('Should not be reached!');
}
};
const [userIngredients, dispatch] = useReducer(ingredientReducer, []);
const [httpState, dispatchHttp] = useReducer(httpReducer, { loading: false, error: null });
const filteredIngredientsHandler = useCallback(filteredIngredients => {
dispatch({ type: 'SET', ingredients: filteredIngredients });
dispatchHttp({ type: 'SEND' });
dispatchHttp({ type: 'RESPONSE' });
dispatch({ type: 'DELETE', id: ingredientId });
}, []);
const clearError = () => {
dispatchHttp({ type: 'CLEAR' });
};

React Performance — useMemo() & useCallback()

  • both to prevent unnecessary re-renders and make your code more efficient
  • cache the function in a functional component with a dependency array

.useCallback() - memorize the actual function

  • avoiding unnecessary renders from the child, change the reference only when dependencies change
  • use it when a function is a dependent on a side effect
  • save a function that does not change so that no new function is generated
  • just like useMemo, not going to re-run the code inside of it unless certain parameter has changed
  • take a function which is useCallback returned, stores to a variable and later you can use it like getItems(1)
  • Returns a memoized callback. useCallback will remember your actual function.
const getItems = useCallback((incrementor) => {	//return us the entire function
return [number + incrementor, number + incrementor + 1, number + incrementor + 2]
}, [number])

.useMemo() - memorize the value from the function

  • run on every render but with cached values, will only use new values when certain dependencies change.
  • useMemo accepts two arguments: a function and a list of dependencies, every time useMemo will first check if any dependencies have changed
  • If not, it will return the cached return value, not calling the function. (memoize, cache, no need to re-compute)
  • If they have changed, useMemo will call the provided function again and repeat the process.
  • Returns a memoized value. useMemo will remember the returned value from your function.
const doubleNumber = useMemo(() => {	//only return the value of the function
return slowerFunction(number)
}, [number])

Context

What is React Context?

  • Context provides a way to pass data through the component tree without having to pass props down manually at every level.
  • With the help of context, we can get the value to the nested children directly.
  • Without Redux and React Context, we have to do lifting state up.

How to use Context

  • export const Context = React.createContext() - initiate the context, and default values, not actually in use but for auto-completion
  • class: Using < Context.Provider value={} > and < Context.Consumer > to wrap the return code
  • function: Using < Context.Provider value={} > and use hook useContext then const value = useContext(Context)

React vs Redux

  • You can have multiple contexts but only one store in Redux
  • If you use React Context, it may cause Data Contamination since the Consumer looks for the nearest Provider ancestry
  • defaultValue <=> bubbling — always go up to look at the closest ancestry
  • In Context, GrandChild.js — Look for the Child value but not the Parent value
  • we could make mistakes, or not be able to get the value we want, since the value passing down to GrandChild, the nearest ancestry is Child

When will be great to use Context?

  • Redux — Larger scale application
  • Context — Smaller scale application

Disadvantages over Redux

  • complex setup/management can lead to deeply nested JSX code and/or huge context provider component
  • performance, react context is not optimized for high-frequency state changes

To read more about Redux click here

--

--

Hanwen Zhang
Hanwen Zhang

Written by Hanwen Zhang

Full-Stack Software Engineer at a Healthcare Tech Company | Document My Coding Journey | Improve My Knowledge | Share Coding Concepts in a Simple Way