Skip to main content
Hero Light

Core React Concepts

In React, props (short for properties) are used to pass data from a parent component to a child component.React automatically provides a props object to every functional component. This object contains all the values passed as attributes when the component is used.

πŸ‘‡ Example:

The parent component (App) passes a prop to the child (User) like this:
const App = () => {
 return <User name="skyWalker" />; // Use curly braces for non-strings like age={18}
};

const User = (props) => {
 console.log(props); // { name: "skyWalker" }
 return <section></section>;
};
The useState hook in React is used to manage local component state.
It always returns an array with two elements:
  1. The current state value
  2. A function to update the state
useState Hook

🧠 Example:

const [count, setCount] = useState(0);
const state = useState(0);
console.log(state); // [0, 1]
Destructuring Convention:We generally destructure using the naming pattern:
const [x, setX] = useState(initialValue);
The useEffect hook lets you run side effects in your React components β€” like fetching data, updating the DOM, or setting up subscriptions.It runs after the component renders, and can be configured to run:
  • After every render
  • Only once on mount
  • Or when specific dependencies change

πŸ”§ Basic Syntax:

useEffect(() => {
  // code here runs after render
}, [dependencies]);
Example 1: Run only on first render
useEffect(() => {
  console.log("Component mounted!");
}, []);
Example 2: Run when a value changes
const [count, setCount] = useState(0);

useEffect(() => {
  console.log("Count changed:", count);
}, [count]);

Example 3: Cleanup function
useEffect(() => {
  const interval = setInterval(() => {
    console.log("Tick...");
  }, 1000);

  return () => clearInterval(interval); // runs on unmount or before re-running
}, []);

The useContext hook lets you share state or values globally across components β€” without manually passing props at every level (aka β€œprop drilling”).It’s perfect for things like:
  • Theme or language settings
  • Auth/user data
  • Global app config or state

🧠 Basic Setup:

// 1️⃣ Create a context
const MyContext = React.createContext();

// 2️⃣ Provide the value somewhere at the top level
<MyContext.Provider value={"Hello"}>
  <Child />
</MyContext.Provider>

// 3️⃣ Consume it anywhere in the tree
const value = useContext(MyContext);
Example:
const ThemeContext = React.createContext();

const App = () => {
 return (
   <ThemeContext.Provider value="dark">
     <Header />
   </ThemeContext.Provider>
 );
};

const Header = () => {
 const theme = useContext(ThemeContext);
 return <h1>Theme: {theme}</h1>; // Theme: dark
};
When to Use:
  • You want to avoid prop drilling
  • You need shared state/data accessible across many components
  • You’re building global providers (theme, user, etc.)
➀ useContext is often used with useReducer or useState to build lightweight global state managers.
The useReducer hook is an alternative to useState for managing more complex state logic β€” especially when:
  • The next state depends on the previous state
  • You want to group related state updates together
  • You’re building Redux-style reducer logic
It uses a reducer function that decides how the state should change based on an action.

🧠 Basic Syntax:

const [state, dispatch] = useReducer(reducerFn, initialState);
  • state β†’ current state value
  • dispatch β†’ function to trigger state changes
  • reducerFn β†’ (state, action) => newState
Example
const reducer = (state, action) => {
switch (action.type) {
  case "increment":
    return { count: state.count + 1 };
  case "decrement":
    return { count: state.count - 1 };
  default:
    return state;
}
};

const Counter = () => {
const [state, dispatch] = useReducer(reducer, { count: 0 });

return (
  <>
    <h2>Count: {state.count}</h2>
    <button onClick={() => dispatch({ type: "increment" })}>+</button>
    <button onClick={() => dispatch({ type: "decrement" })}>-</button>
  </>
);
};
➀ useReducer makes your state transitions more predictable, testable, and scalable in larger components.
The useRef hook in React is used to access DOM elements directly or to store mutable values that don’t trigger re-renders.It returns a ref object with a .current property that you can update or read.

🧠 Syntax:

const myRef = useRef(initialValue);
Storing mutable values (like instance variables):
const countRef = useRef(0);

useEffect(() => {
  const interval = setInterval(() => {
    countRef.current += 1;
    console.log("Count (not reactive):", countRef.current);
  }, 1000);

  return () => clearInterval(interval);
}, []);

When to Use:
  • To directly manipulate DOM elements (like .focus(), .scrollIntoView())
  • To persist data across renders without re-rendering the component
  • To store previous values or timeout/interval IDs
➀ useRef is great when you want to persist a value without causing a re-render β€” unlike useState.
React Suspense is a feature that lets you wait (β€œsuspend”) rendering of a component until some async operation is done, like data fetching or lazy-loading.Old Way:
if (!data) return <div>Loading...</div>
return <div>{data.name}</div>
With Suspense:
<Suspense fallback={<div>Loading...</div>}>
  <Profile />
</Suspense>
use() lets you directly await promises inside a component β€” especially useful for:
  • Async components (like await import() / fetch)
  • Server components (React Server Components)
  • Data fetching during rendering
But React doesn’t know when the promise will resolve β€” so it needs a Suspense boundary to pause and show a fallback UI until the promise completes.Old Way:
const [data, setData] = useState(null);

useEffect(() => {
  fetch('/api/data')
    .then(res => res.json())
    .then(setData);
}, []);

With use:
const data = use(fetch('/api/data').then(res => res.json()));