Props are used to pass data from parent to child component — they are read-only, meaning child cannot modify them. State is data that lives inside a component — when state changes, the component re-renders automatically. For example, in a product card, the product name comes from props passed by parent, but a 'liked' button toggle would use state inside that component.
Props are immutable and controlled by the parent, while state is mutable and controlled by the component itself. Props are used for data that doesn't change within the component, while state is used for data that can change based on user interaction or other factors.
Prop drilling is passing props through many intermediate components that don't use them, just to pass to child components. Example: <A> → <B> → <C> where B doesn't need the prop. Solutions: use Context API to share data globally without prop drilling, use state management like Redux.
Context API in React is a built-in state management feature that helps share data across multiple components without prop drilling.
It allows us to create global state, such as authentication data, themes, or language settings, and access it anywhere in the component tree.
PROBLEM IT SOLVES
- Prop drilling — passing props through many intermediate components that don't even need the data.
WHEN TO USE CONTEXT API
Use for global/shared state like:
- Logged-in user (authentication)
- Theme (dark/light mode)
- Language/locale settings
- Cart items
- Application-wide notifications
IMPLEMENTATION EXAMPLE
First I create the context with createContext(null) — null because no data exists yet. Then I make an AuthProvider component that holds my state and functions, and wraps everything with AuthContext.Provider value={{user, login, logout}}. I wrap my App with this Provider so all children get access. Then I make a custom hook useAuth() which internally calls useContext — so in any component I just write const { user } = useAuth() and I get my data. No prop drilling at all.
COMMON CONCERNS
Does Context API cause unnecessary re-renders?
Yes! Every component using useContext re-renders when the context value changes. Fix: split contexts (e.g. separate UserContext and ThemeContext) or use useMemo on the value.
What is the difference between useContext and Consumer?
Older way was using <Context.Consumer> with render props — it was messy and hard to read. With hooks, useContext() is much cleaner and readable. I always use useContext in functional components.
What happens if you use useContext outside the Provider?
It will get the default value that was passed to createContext() — in our case null. That's why I always make sure to wrap the component tree with the Provider in App.jsx.
Can you have multiple contexts in one app?
Yes, I split them by responsibility — AuthContext for user data, ThemeContext for dark/light mode. This also avoids unnecessary re-renders because changing theme won't re-render components that only use AuthContext.
How do you optimize Context to avoid re-renders?
I wrap the value in useMemo so it only changes when the actual data changes — not on every render of the Provider component.
CONTEXT API VS REDUX
I would use Context API for small to medium applications where the state management is simple, such as:
- Theme switching
- User authentication data
- Language settings
- Basic shared state
Because Context API is built into React, it is lightweight and easy to set up.
For large-scale applications with complex state management, I would prefer Redux because it provides:
- Centralized state management
- Predictable state updates
- Better debugging with Redux DevTools
- Middleware support like async API handling using Redux Thunk or Redux Toolkit
- Better scalability and maintainability
Redux is especially useful when many components need to access and update shared state frequently.
Redux is a centralized state management library used mainly in React applications.
PROBLEMS WITH CONTEXT API
Context API works well for small applications, but in large-scale applications it can become difficult to manage state efficiently. Main problems:
- Unnecessary Re-renders: When the context value changes, all consuming components re-render.
- Hard to Debug: Difficult to track state changes and trace where updates come from.
- Difficult in Large Applications: Managing complex state logic becomes challenging as the app grows.
WHAT IS REDUX?
Instead of managing state separately inside multiple components, Redux stores the entire application state in a single centralized store.
Any component can access the state or update it by dispatching actions.
State updates happen in a predictable and structured way using reducers.
Redux follows a unidirectional data flow, which makes state management predictable and easier to debug.
REDUX FLOW
Component → Dispatch Action → Reducer → Store Updates → UI Re-renders
REDUX CORE CONCEPTS (3 Main Things)
1. Store
- Store is the central place where the entire application state is stored.
- It contains all global data of the application.
2. Action
- Action is a plain JavaScript object that describes what happened.
- It tells Redux what type of update should happen.
3. Reducer
- Reducer is a pure function that takes current state and action, then returns updated state.
WHY REDUX TOOLKIT (RTK)?
Plain Redux had too much boilerplate code and setup.
We had to create separate actions, reducers, and constants files, which made code lengthy and harder to manage.
Redux Toolkit simplifies Redux by reducing boilerplate, providing easier store setup, and making state updates simpler.
WHAT IS REDUX TOOLKIT (RTK)?
Redux Toolkit is the official, recommended way to write Redux. It removes all the boilerplate. Same Redux under the hood — but with less code, better structure, and built-in tools.
IMPORTANT CONCEPTS IN RTK
useSelector and useDispatch
- useSelector is used to read state from the store.
- useDispatch gives me the dispatch function to update state by sending actions.
What is a Slice in RTK?
- A slice is a single feature's state + reducers + actions — all in one file.
- For example authSlice handles everything related to authentication.
- This keeps code organized and colocates related logic.
How do you handle Async API calls in Redux? (Important ⭐)
- I use createAsyncThunk from RTK.
- It handles 3 states automatically — pending, fulfilled, rejected — which I use to show loading, success, or error UI.
What is Redux DevTools?
- It's a browser extension that lets me see every action that was dispatched, the state before and after, and even time-travel to a previous state.
- RTK enables it automatically — no extra setup needed.
- Extremely useful for debugging complex state updates and understanding state flow.
Zustand is a lightweight state management library for React applications. It provides a simple API for managing global state without the complexity of Redux. Zustand allows you to create stores with a minimal API, making it easy to manage and scale your application's state. It supports middleware and is designed to be easy to use while still providing powerful features for complex state management scenarios.