React. Basics and Questions
1. Lifecycle
In React, class components used to have lifecycle methods that allowed developers to perform certain actions at different stages of a component’s life. However, with the release of React 16.3, many of these lifecycle methods were deprecated in favor of new ones introduced as part of the React Hooks API.
Mounting Phase:
constructor
: The component is initialized.static getDerivedStateFromProps
: This method is called before every render.render
: The component renders.componentDidMount
: This method is called after the component has been rendered to the DOM.
Updating Phase:
static getDerivedStateFromProps
: Again, this method is called before every render.shouldComponentUpdate
: This method can be used to control whether the component should re-render or not.render
: The component re-renders if necessary.getSnapshotBeforeUpdate
: This method is called right before the changes from the virtual DOM are to be reflected in the actual DOM.componentDidUpdate
: This method is called after the component has been updated in the DOM.
Unmounting Phase:
componentWillUnmount
: This method is called before the component is removed from the DOM.
Error Handling:
componentDidCatch
: Invoked when an error occurs during rendering, in a lifecycle method, or in the constructor of any child component.
class MyComponent extends Component {
constructor(props) {
super(props)
this.state = { count: 0 }
}
// Custom method
updateState() {
this.setState({ count: this.state.count + 1 })
}
// Lifecycles
componentDidMount() {
console.log('Component did mount')
}
componentDidUpdate(prevProps, prevState) {
console.log('Component did update')
}
componentWillUnmount() {
console.log('Component will unmount')
}
render() {
return <div>Count: {this.state.count}</div>
}
}
export default MyComponent
2. Hooks
useEffect
It allows to perform side effects in function components, such as synchronizing props and state, fetching data, managing subscriptions, or manually manipulating the DOM in React components.
useEffect(() => {
// Side effect logic here
}, [dependency])
The second argument is an optional array of dependencies. useEffect
will only re-run the side effect if one of the dependencies has changed since the last render. If you pass an empty array ([]
), the effect will only run once after the initial render, mimicking the behavior of componentDidMount
in class components.
// Running once on mount (like componentDidMount):
useEffect(() => {
// Code to run on component mount
}, []) // Only runs once
// Running on specific state/prop changes (like componentDidUpdate):
useEffect(() => {
// Code to run when specific props or state change
}, [prop, state])
// Cleaning up (like componentWillUnmount)
useEffect(() => {
// Setup code
return () => {
// Cleanup code
}
}, [])
useState
Is a Hook in React that lets to add state to functional components. Introduced in React 16.8, Hooks are functions that let you “hook into” React state and lifecycle features from function components. Before Hooks, stateful logic in React could only be used in class components.
import React, { useState } from 'react'
function Counter() {
// Declare a new state variable, which we'll call "count"
const [count, setCount] = useState(0)
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
export default Counter
// Note
function handleClick() {
setAge(age + 1) // setAge(42 + 1)
setAge(age + 1) // setAge(42 + 1)
setAge(age + 1) // setAge(42 + 1)
}
function handleClick() {
setAge(a => a + 1) // setAge(42 => 43)
setAge(a => a + 1) // setAge(43 => 44)
setAge(a => a + 1) // setAge(44 => 45)
}
// Never mutate the state
// NO
form.firstName = 'Taylor'
// YES
setForm({
...form,
firstName: 'Taylor'
})
(!) If you want to reset the entire component tree’s state, pass a different key
to your component.
(!) Calling the set
function does not change state in the running code.
useRef
Is a Hook in React that allows you to persistently store a mutable value that does not cause re-renders when it is changed. It’s similar to having a class instance property in a class component. The useRef
Hook is useful for a variety of purposes, such as accessing a DOM element directly, storing a previous value, or keeping a mutable reference to a value that doesn’t trigger re-renders when updated.
// Initializing
const myRef = useRef(initialValue)
// Accessing
console.log(myRef.current) // Outputs the initialValue
// - Accessing DOM Elements
function MyComponent() {
const inputEl = useRef(null)
const onButtonClick = () => {
// `current` points to the mounted text input element
inputEl.current.focus()
}
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
)
}
// - Storing Previous State or Props
const prevPropsRef = useRef(props)
useEffect(() => {
// Compare current props with previous props
if (prevPropsRef.current !== props) {
// Do something with the updated props
}
// Update prevPropsRef with the latest props
prevPropsRef.current = props
}, [props])
// - Storing Mutable Values
function TimerComponent() {
const intervalId = useRef()
useEffect(() => {
intervalId.current = setInterval(() => {
console.log('Timer tick')
}, 1000);
return () => clearInterval(intervalId.current)
}, [])
// Other logic
}
useCallback
Is a hook in React that is used to memoize functions. This hook is useful when you need to pass callbacks to optimized child components that rely on reference equality to prevent unnecessary renders.
const memoizedCallback = useCallback(
() => {
// Your function logic here
},
[/* dependencies */],
)
If you pass an empty array ([]
), the callback will only be created once, meaning this useCallback does not depend on any external values, similar to componentDidMount
in class components.
Suppose you have a component <Child>
that should only re-render when its props change. If you pass a non-memoized function as a prop, <Child>
will re-render every time the parent component renders, even if the function logic hasn't changed.
const Child = React.memo(({ onIncrement }) => {
console.log('Child render')
return <button onClick={onIncrement}>Increment</button>
})
const ParentComponent = ({val}) => {
const [value, setValue] = React.useState(val)
const increment = useCallback(() => {
setValue(v => v + 1)
}, [val])
return <Child onIncrement={increment} />
}
useMemo
Is a hook in React that memoizes the value returned by a function. This means that it saves the result of an expensive function call and only recalculates this result when one of its dependencies changes. The purpose of useMemo
is to optimize performance by avoiding expensive calculations on every render. Can help by memoizing these values and preventing unnecessary renders.
const cachedValue = useMemo(calculateValue, dependencies)
// calculateValue should be pure, should take no arguments, and should return a value of any type.
// dependencies - are reactive values include props, state, and all the variables and functions declared directly inside your component body.
function MyComponent({ a, b }) {
const expensiveResult = useMemo(() => {
// An expensive operation that only needs to run when a or b changes
return computeExpensiveValue(a, b)
}, [a, b])
return <div>Result: {expensiveResult}</div>
}
If you pass an empty dependencies array ([]
) to useMemo
in React, it means that the memoized value will only be computed once, when the component mounts.
useReducer
Is a React hook that provides a way to manage more complex state logic by dispatching actions to a reducer function, which specifies how the state should be updated based on the current state and an action, offering an alternative to useState
for handling state in certain scenarios.
Use Cases: (1) Complex state interactions. (2) When the next state depends heavily on the previous one. (3) When you want to encapsulate state management logic. (4) For easier integration with state management libraries like Redux.
import React, { useReducer } from 'react';
const initialState = { count: 0 }
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 }
case 'decrement':
return { count: state.count - 1 }
default:
throw new Error()
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState)
return (
<>
Count: {state.count}
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
</>
);
}
useContext
Provides a way to pass data through the component tree without having to pass props down manually at every level. Context provides a way to share values like these between components without having to explicitly pass a prop through every level of the tree.
Don’t overuse the Context API. It’s meant for global data (like themes, user data), not for all state management scenarios.
import React, { useContext, createContext } from 'react';
// Create a Context
const ThemeContext = createContext('light')
function App() {
return (
<ThemeContext.Provider value='dark'>
<Toolbar />
</ThemeContext.Provider>
)
}
function Toolbar() {
return (
<div>
<ThemedButton />
</div>
)
}
function ThemedButton() {
// Use the context value
const theme = useContext(ThemeContext)
return <button theme={theme}>I am styled by theme context!</button>
}
3. APIs
memo
Is a higher-order component that can be used to optimize functional components by preventing unnecessary renders. If the component’s props or state change, the component will re-render.
const MyComponent = React.memo((props) => {
// Component logic and rendering based on props
return (
<div>
{/* Render something based on props */}
</div>
)
})
// Usage of MyComponent in another component
function ParentComponent() {
const someProps = // ... some dynamic props
return (
<div>
<MyComponent {...someProps} />
</div>
)
}
lazy
Is used to enable code-splitting for components, allows to break down the bundle into smaller chunks, and then load these chunks on-demand, typically when a user navigates to a specific part of your application.
The lazy
function is often used in conjunction with the Suspense
component to handle the asynchronous loading of code-split components.
import React, { Suspense } from 'react'
const MyComponent = React.lazy(() => import('./MyComponent'))
function App() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<MyComponent />
</Suspense>
</div>
);
}
createContext
Is a function that is part of the React context API. The context API is designed to share values, such as state or functions, between components without explicitly passing them through every level of the component tree. createContext
creates a context object, and it returns two components: Provider
and Consumer
.
import React, { useContext } from 'react'
// Create a context with a default value
const MyContext = React.createContext('some value')
// Component that provides the context value using the Provider
function MyProvider({ children }) {
const contextValue = 'value from provider';
return <MyContext.Provider value={contextValue}>{children}</MyContext.Provider>;
}
// Component that consumes the context
function MyFunctionalConsumer() {
const contextValue = useContext(MyContext) // useContext instead of the Consumer
return <div>Context value: {contextValue}</div>
}
4. React-dom
createPortal
Is a method that allows you to render a React component's children into a different DOM element outside of the component's parent hierarchy. This is useful in situations where you need to render content in a different part of the DOM, like a modal or a tooltip, while keeping the logical structure of your React components intact.
ReactDOM.createPortal(child, container)
import React, { useState } from 'react'
import ReactDOM from 'react-dom'
const PortalExample = () => {
const [showPortal, setShowPortal] = useState(false)
const togglePortal = () => {
setShowPortal(!showPortal)
}
return (
<div>
<button onClick={togglePortal}>Toggle Portal</button>
{showPortal && (
ReactDOM.createPortal(
<div className="portal-content">
This content is rendered outside the root of the React app.
</div>,
document.getElementById('portal-root') // a DOM element outside the main app root
)
)}
</div>
);
};
export default PortalExample
child
: The React element or component you want to render.container
: A reference to the DOM element where thechild
should be rendered.
Questions
1. What is the Virtual DOM in React
The Virtual DOM in React is a lightweight, in-memory representation of the actual DOM. It is used to optimize and speed up the process of updating the user interface. React updates the Virtual DOM first, calculates the minimal changes needed, and then efficiently updates the real DOM, reducing direct interactions and improving performance.
2. Difference between DOM and Virtual DOM.
The DOM is the live representation of a webpage rendered by the browser, while the Virtual DOM is an in-memory, efficient copy used by React to optimize updates before applying them to the actual DOM.
3. What is JSX?
JSX, or JavaScript XML, is a syntax extension for JavaScript that allows developers to write declarative, HTML-like code within JavaScript.
4. What is render in React?
“Render” refers to the process of converting React components into actual DOM elements that can be displayed on the user interface. Reflects any changes in the component’s state or props, ensuring that the UI reflects the current application state.
5. What are the components in React?
Components are the fundamental building blocks of a user interface. There are two main types of components in React: Functional and Class Components.
6. What are props and what are the main differences with state?
Props are parameters passed into React components for communication between parent and child components, while state is a built-in object for managing a component’s internal data and triggering re-renders.
7. How to update the state?
Using use of the useState
hook to define and update a state variable. It gives back an array that holds the state variable in the first position and the
setter setState
.
8. What are synthetic events in React?
Synthetic Events in React are wrapper objects that provide a consistent interface for handling events across different browsers, optimizing browser-specific differences.
9 .What is ref in React?
Refs are variables created using the useRef
hook to store non-rendering, mutable values, allowing access via the ref.current
key; a common use case is (1) accessing a DOM element directly, (2) storing a previous value, or (3) keeping a mutable reference to a value that doesn’t trigger re-renders when updated.
10. How does React render process work?
(1) Triggering a render (delivering) >>
(2) Rendering the component (preparing) >>
(3) Committing to the DOM (placing)
11. How to reuse logic in functional components?
You can use custom hooks. Custom hooks are JavaScript functions that start with “use” and can encapsulate and share logic across multiple components
// useCounter.js
import { useState } from 'react'
const useCounter = (initialValue) => {
const [count, setCount] = useState(initialValue)
const increment = () => {
setCount(count + 1)
}
const decrement = () => {
setCount(count - 1)
}
return { count, increment, decrement }
}
export default useCounter
// ComponentA.js
import React from 'react'
import useCounter from './useCounter'
const ComponentA = () => {
const { count, increment, decrement } = useCounter(0)
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
</div>
)
}
12. What are keys in React and why it’s important to use them?
Keys in React are special attributes that provide a unique identifier to elements in a list, enabling efficient updates and reconciliation by helping React identify changes, additions, or removals during rendering. Crucial in arrays, during sorting, adding, deleting elements.
13. Difference between a controlled and uncontrolled component in React?
Controlled components depend on the parent component, its behavior and state, using props for updates, while uncontrolled components manage their own state internally.
14. The main difference between server side rendering (SSR) and client side rendering in React.
Server-side rendering in React involves generating HTML on the server and sending it to the client, while client-side rendering involves sending minimal HTML to the client and using JavaScript to render the UI on the browser.
15. How to avoid unnecessary renders in a React component?
Wrapping received props with useCallback
or useMemo
and applying React.memo
to the component itself, ensuring it only updates when specific props change. Additionally, reviewing the useEffect
calls within the component can identify and prevent unnecessary renders.
16. What is a Portal in React?
a Portal is a feature that allows you to render a component’s children into a different part of the DOM hierarchy than where the parent component is actually located. Useful to create a modal.
17. The main difference between useEffect
and useLayoutEffect
useEffect
runs asynchronously after the browser paints, while useLayoutEffect
runs synchronously before painting, making it suitable for tasks requiring immediate DOM access and layout calculations.
18. Where to load the data in React?
componentDidMount
for class components or in the useEffect
hook for functional components, allowing you to perform asynchronous operations like fetching data from APIs or other sources after the component has mounted.
19. What are hooks in React?
Functional approach to dealt with state and lifecycles inside functional components.
20. How can you make a functional component perform an action only once on initial render?
useEffect
hook with an empty dependency array. The empty array ensures that the effect runs only after the first render and not on subsequent updates.
useEffect(() => {
// Perform the action here
console.log('This runs only once after the initial render')
}, []) // Empty dependency array
21. What is prop-drilling, and how to avoid it?
Prop drilling refers to the process of passing down props through multiple layers of nested components, even if the intermediate components do not use those props.
To avoid prop drilling, you can use techniques like: Context API, using State Managers (Redux), Custom Hooks, Component Composition (combining or composing smaller, more focused components together).
22. How can you reset a component’s state to it’s initial state?
Of using an Initial State record or passing a key value.
const MyComponent = () => {
const initialState = { /* your initial state values */ }
const [state, setState] = useState(() => initialState)
return (
<div>
<button onClick={() => setState(initialState)}>Reset to Initial State</button>
</div>
)
}
const ParentComponent = () => {
// Use a state to track the key
const [key, setKey] = useState(0)
const resetComponent = () => {
// Increment the key to force remounting of MyComponent
setKey(prevKey => prevKey + 1)
}
return (
<div>
<MyComponent key={key} />
<button onClick={resetComponent}>Reset Component</button>
</div>
)
}
23. The difference between useState
and useEffect
.
useState
is used for managing state in functional components, while useEffect
is employed for handling side effects, allowing functional components to have state and perform additional tasks like data fetching or DOM manipulations.
24. Where would you get the key value for a component?
(1) Using Unique IDs if the data coming from the data base, (2) using Index as Key for the iterable data.
25. Explain lazy loading.
Lazy loading in React involves loading parts of your application only when they are needed, NOT during the initial load. This is often achieved using React.lazy()
to dynamically import components and the Suspense
component to handle loading states. The goal is to reduce the initial bundle size, prioritize critical parts for faster load times, and improve overall performance in larger applications.
26. Differences between useMemo
and useCallback
.
useMemo
is used to memoize the result of a computation, while useCallback
is used to memoize a callback function, both aiming to optimize performance by preventing unnecessary recalculations or recreations.
27. Why use forwardRef
?
forwardRef
lets your component expose a DOM node to parent component with a ref.
28. When does the useEffect
cleanup function run?
The cleanup function in the useEffect
hook runs right before the component unmounts and before the useEffect
runs again due to dependency changes.
29. Explain the concept of Reducers and Context in React.
Reducers in React manage state transitions through specified actions, while Context provides a way to share values globally across components.
30. How to catch render errors in React components at the global scope?
you can catch render errors at the global scope using the componentDidCatch
lifecycle method in a class component or the useErrorBoundary
hook in a functional component combined with an error boundary component to encapsulate the error-handling logic.
class ErrorBoundary extends React.Component {
constructor(props) {
super(props)
this.state = { hasError: false }
}
static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
return { hasError: true }
}
componentDidCatch(error, errorInfo) {
// You can also log the error to an error reporting service
console.log(error, errorInfo)
}
render() {
if (this.state.hasError) {
// You can render any custom fallback UI
return <h1>Something went wrong.</h1>
}
return this.props.children
}
}
// Then you can use it as a regular component to wrap any part of your app
const App = () => {
return (
<ErrorBoundary>
<MyComponent />
</ErrorBoundary>
)
}
31. How does useEffect
check changes in its array dependency?
useEffect
checks its dependencies by comparing each one to its previous value using Object.is
. Objects and arrays are compared based on their memory reference, while primitive values like numbers and strings are compared based on their actual value.