Q6: What is state in React and how is it different from props?
State is an object managed within a component that holds information that may change over the component's lifecycle. Unlike props, which are passed to a component from its parent, state is local to the component and can be updated with the
setState
method in class components or the
useState
hook in functional components.
Differences between State and Props:
State:
Example:
class ExampleComponent extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
increment = () => {
this.setState({ count: this.state.count + 1 });
}
render() {
return (
Count: {this.state.count}
);
}
}
Props:
Example:
function DisplayMessage(props) {
return {props.message}
;
}
function ParentComponent() {
return ;
}
Q7: What is the context API in React and when would you use it?
The Context API in React provides a way to pass data through the component tree without having to pass props down manually at every level. It is useful for sharing data that needs to be accessed by many components at different nesting levels, such as themes, user authentication, or locale settings.
Usage:
Create a Context:
const MyContext = React.createContext();
Provide Context Value:
function App() {
return (
);
}
Consume Context Value:
Using
Context.Consumer
:
function ChildComponent() {
return (
{value => {value}
}
);
}
Using
useContext
Hook (functional components):
function ChildComponent() {
const value = React.useContext(MyContext);
return {value}
;
}
Q8: How do you handle events in React?
Event handling in React is similar to handling events in DOM elements but with some syntactic differences. React events are named using camelCase, and you pass a function as the event handler rather than a string.
Example:
class ClickComponent extends React.Component {
handleClick = () => {
alert('Button clicked!');
}
render() {
return (
);
}
}
In functional components, you can handle events using hooks:
function ClickComponent() {
const handleClick = () => {
alert('Button clicked!');
};
return (
);
}
Q9: What are higher-order components (HOCs) in React?
A higher-order component (HOC) is a function that takes a component and returns a new component with additional props or functionality. HOCs are used to reuse component logic.
Example:
function withLogging(WrappedComponent) {
return class extends React.Component {
componentDidMount() {
console.log('Component mounted:', WrappedComponent.name);
}
render() {
return ;
}
};
}
const EnhancedComponent = withLogging(MyComponent);
In this example,
withLogging
is an HOC that adds logging functionality to the
MyComponent
component.
Q10: What are React fragments and why would you use them?
React fragments let you group a list of children without adding extra nodes to the DOM. This is useful when rendering multiple elements from a component without wrapping them in an extra div or other container element.
Example:
function FragmentComponent() {
return (
Title
Description
);
}
Shorthand syntax for fragments:
function FragmentComponent() {
return (
<>
Title
Description
);
}
Fragments are used to avoid unnecessary HTML elements in the DOM, which can simplify CSS styling and improve performance.
Request question
Please fill in the form below to submit your question.
Q11: What is the purpose of useEffect in React and how does it work?
The
useEffect
hook allows you to perform side effects in functional components. Side effects include data fetching, subscriptions, and manually changing the DOM.
useEffect
runs after the render and ensures the component logic is separate from the side effects.
Syntax:
useEffect(() => {
// Side effect logic
return () => {
// Cleanup logic
};
}, [dependencies]);
Parameters:
Example:
import React, { useState, useEffect } from 'react';
function ExampleComponent() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]); // Only re-run the effect if count changes
return (
You clicked {count} times
);
}
Q12: What is the useState hook and how do you use it in React?
The
useState
hook allows you to add state to functional components. It returns an array containing the current state value and a function to update that state.
Syntax:
const [state, setState] = useState(initialState);
Parameters:
Example:
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
You clicked {count} times
);
}
In this example,
count
is the state variable and
setCount
is the function to update
count
. The initial state is set to 0.
Q13: Explain the concept of lifting state up in React.
Lifting state up is a pattern in React where you move state from child components to their closest common ancestor. This allows multiple components to share and synchronize their state.
Scenario: Suppose you have two sibling components that need to share the same state. Instead of managing state separately in each component, you lift the state up to their parent component and pass it down as props.
Example:
function ParentComponent() {
const [sharedState, setSharedState] = useState('');
return (
);
}
function ChildComponentA({ sharedState, setSharedState }) {
return (
setSharedState(e.target.value)} />
);
}
function ChildComponentB({ sharedState }) {
return (
{sharedState}
);
}
In this example,
sharedState
is lifted up to
ParentComponent
, allowing both
ChildComponentA
and
ChildComponentB
to access and synchronize the state.
Q14: What are controlled and uncontrolled components in React?
Controlled Components: These are components where React controls the form elements by keeping the form data in the component state. The value of the form element is set by the state and updated via events.
Example:
function ControlledInput() {
const [value, setValue] = useState('');
return (
setValue(e.target.value)} />
);
}
Uncontrolled Components: These are components where the form data is handled by the DOM itself. You can use a ref to access the form values.
Example:
function UncontrolledInput() {
const inputRef = useRef(null);
const handleSubmit = () => {
alert(inputRef.current.value);
};
return (
);
}
Controlled components are preferred because they provide a more predictable and manageable way to handle form inputs.
Q15: How do you optimize performance in a large React application?
To optimize performance in a large React application, you can follow these best practices:
React.memo
to memoize functional components to prevent unnecessary re-renders.
const MyComponent = React.memo(function MyComponent(props) {
/* render using props */
});
useCallback
to memoize callback functions.
const memoizedCallback = useCallback(() => {
doSomething(a, b);
}, [a, b]);
useMemo
to memoize expensive calculations.
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
React.lazy
to load components lazily.
const OtherComponent = React.lazy(() => import('./OtherComponent'));
react-window
or
react-virtualized
to render only visible items in a large list.
function handleClick() {
// handle click
}
return ;
shouldComponentUpdate
or
React.PureComponent
in class components and
React.memo
in functional components.
By applying these techniques, you can significantly improve the performance of your React application.
Request question
Please fill in the form below to submit your question.
Q16: What are React Portals and when would you use them?
React Portals provide a way to render children into a DOM node that exists outside the hierarchy of the parent component. They are useful for scenarios where you need to break out of the normal DOM hierarchy, such as rendering modals, tooltips, or dropdowns that overlay other content.
Syntax:
ReactDOM.createPortal(child, container);
Example:
import React from 'react';
import ReactDOM from 'react-dom';
function Modal({ children }) {
return ReactDOM.createPortal(
{children}
,
document.getElementById('modal-root')
);
}
function App() {
return (
App Component
This is a modal content
);
}
In this example, the modal content is rendered into the
modal-root
div, which is outside the normal DOM hierarchy of the
App
component.
Q17: What are error boundaries in React and how do you implement them?
Error boundaries are React components that catch JavaScript errors anywhere in their child component tree, log those errors, and display a fallback UI instead of the component tree that crashed. They help prevent the entire application from crashing due to an error in a part of the UI.
Implementation:
Create an Error Boundary Component:
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
// Log error details
console.error("Error caught by Error Boundary:", error, errorInfo);
}
render() {
if (this.state.hasError) {
return Something went wrong.
;
}
return this.props.children;
}
}
Wrap Your Components with Error Boundary:
function App() {
return (
);
}
Error boundaries catch errors during rendering, in lifecycle methods, and in constructors of the whole tree below them.
Q18: Explain the concept of reconciliation in React.
Reconciliation is the process by which React updates the DOM with the results of render output. When the state or props of a component change, React compares the newly returned element with the previously rendered one and updates the actual DOM only where there are differences.
Steps in Reconciliation:
to
).
Example:
function App() {
const [items, setItems] = useState(['A', 'B', 'C']);
return (
{items.map(item => (
- {item}
))}
);
}
Using keys, React can efficiently update the list when items are added, removed, or reordered.
Q19: What is the purpose of useReducer hook and how does it work?
The
useReducer
hook is an alternative to
useState
for managing complex state logic in functional components. It is particularly useful when the state depends on previous state values or when multiple state transitions share logic.
Syntax:
const [state, dispatch] = useReducer(reducer, initialState);
Parameters:
Example:
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}
);
}
In this example,
useReducer
manages the state transitions based on the dispatched actions.
Q20: Explain the difference between componentDidMount and useEffect in React.
componentDidMount
is a lifecycle method used in class components, while
useEffect
is a hook used in functional components. Both are used to perform side effects, such as data fetching, subscriptions, or manually modifying the DOM, after the component has been rendered to the DOM.
componentDidMount:
Example:
class MyComponent extends React.Component {
componentDidMount() {
console.log('Component did mount');
}
render() {
return Hello, World!;
}
}
useEffect:
Example:
import React, { useEffect } from 'react';
function MyComponent() {
useEffect(() => {
console.log('Component did mount');
}, []); // Empty array means it runs once after the initial render
return Hello, World!;
}
Differences:
componentDidMount
is for class components, while
useEffect
is for functional components.
useEffect
can handle multiple effects and can be configured to run based on dependencies.
useEffect
, you can return a cleanup function that runs when the component is unmounted or before the effect runs again.
Request question
Please fill in the form below to submit your question.
Request question
Please fill in the form below to submit your question.
(Basic)
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
const incrementCount = () => {
setCount(count + 1);
};
return (
Count: {count}
);
}
export default Counter;
The code itself does not contain any bugs. However, ensure that there are no external issues such as incorrect imports or render issues in the parent component.
(Basic)
import React, { useState } from 'react';
function TodoList() {
const [todos, setTodos] = useState([]);
const [input, setInput] = useState('');
const addTodo = () => {
setTodos([...todos, input]);
setInput('');
};
const removeTodo = (index) => {
setTodos(todos.filter((_, i) => i !== index));
};
return (
setInput(e.target.value)} />
{todos.map((todo, index) => (
-
{todo}
))}
);
}
export default TodoList;
(Basic)
import React, { useState } from 'react';
function ToggleMessage() {
const [isVisible, setIsVisible] = useState(true);
const toggleVisibility = () => {
setIsVisible(!isVisible);
};
return (
{isVisible && The message is visible
}
);
}
export default ToggleMessage;
The code itself is correct and should work as expected. Ensure there are no external issues such as incorrect imports or render issues in the parent component.
(Intermediate)
import React, { useState, useEffect } from 'react';
function DataFetchingComponent() {
const [data, setData] = useState(null);
useEffect(() => {
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => setData(data));
});
return (
{data ? {JSON.stringify(data, null, 2)}
: 'Loading...'}
);
}
export default DataFetchingComponent;
Add an empty dependency array to the
useEffect
hook to ensure the data is fetched only once when the component mounts.
import React, { useState, useEffect } from 'react';
function DataFetchingComponent() {
const [data, setData] = useState(null);
useEffect(() => {
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => setData(data));
}, []); // Empty array means the effect runs only once
return (
{data ? {JSON.stringify(data, null, 2)}
: 'Loading...'}
);
}
export default DataFetchingComponent;
(Intermediate)
import React, { useState } from 'react';
function ParentComponent() {
const [count, setCount] = useState(0);
const items = ['Item 1', 'Item 2', 'Item 3'];
return (
{items.map((item, index) => (
))}
);
}
function ListItem({ item }) {
console.log('ListItem rendered:', item);
return {item} ;
}
export default ParentComponent;
Use
React.memo
to memoize the
ListItem
component.
import React, { useState } from 'react';
function ParentComponent() {
const [count, setCount] = useState(0);
const items = ['Item 1', 'Item 2', 'Item 3'];
return (
{items.map((item, index) => (
))}
);
}
const ListItem = ({ item }) => {
console.log('ListItem rendered:', item);
return {item} ;
};
const MemoizedListItem = React.memo(ListItem);
export default ParentComponent;
(Intermediate)
import React, { useState } from 'react';
function SearchInput() {
const [query, setQuery] = useState('');
const handleChange = (e) => {
setQuery(e.target.value);
};
return (
Search query: {query}
);
}
export default SearchInput;
Use a debouncing technique to delay the state update.
import React, { useState, useEffect } from 'react';
function SearchInput() {
const [query, setQuery] = useState('');
const [displayedQuery, setDisplayedQuery] = useState('');
useEffect(() => {
const handler = setTimeout(() => {
setDisplayedQuery(query);
}, 300);
return () => {
clearTimeout(handler);
};
}, [query]);
const handleChange = (e) => {
setQuery(e.target.value);
};
return (
Search query: {displayedQuery}
);
}
export default SearchInput;
(Intermediate)
import React, { useState } from 'react';
function LoginForm() {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
alert(`Username: ${username}, Password: ${password}`);
};
return (
);
}
export default LoginForm;
(Advanced)
import React, { useState } from 'react';
function ParentComponent() {
const [count, setCount] = useState(0);
return (
);
}
function ChildComponent() {
console.log('Child component rendered');
return Child Component;
}
export default ParentComponent;
Use
React.memo
to memoize the
ChildComponent
and prevent it from re-rendering unless its props change.
import React, { useState } from 'react';
function ParentComponent() {
const [count, setCount] = useState(0);
return (
);
}
const ChildComponent = () => {
console.log('Child component rendered');
return Child Component;
};
const MemoizedChildComponent = React.memo(ChildComponent);
export default ParentComponent;
(Advanced)
import React, { useState } from 'react';
function OutputComponent() {
const [count, setCount] = useState(0);
const handleClick = () => {
setCount(count + 1);
setCount(count + 1);
};
return (
Count: {count}
);
}
export default OutputComponent;
The output will be:
Count: 1
Explanation:
setCount
does not update the state immediately. It schedules an update, and the state updates are batched. Both
setCount
calls will be batched, and only the last one will be applied, resulting in
count
being incremented by 1 instead of 2.
(Advanced)
import React, { useState } from 'react';
function OutputComponent() {
const [count, setCount] = useState(0);
const handleClick = () => {
setCount(prevCount => prevCount + 1);
setCount(prevCount => prevCount + 1);
};
return (
Count: {count}
);
}
export default OutputComponent;
The output will be:
Count: 2
Explanation: Using the functional update form of
setCount
ensures that the state updates are based on the previous state. This results in
count
being incremented by 1 twice, leading to an increment of 2 when the button is clicked twice.
Request question
Please fill in the form below to submit your question.
Overview of React