React

Last Updated: 3/27/2023

Managing Component State

Understanding State Hook

  • State hook: allows us to add state to function components.
  • Hooks can only be called at the top of components: You can't use hook inside of for loop, if else and nested functions. React relies on the order of hook so it can map the values to the local variable inside the function
  • State is stored outside of the component: State variables, unlike local variables in a function, stay in memory as long as the component is visible on the screen. This is because state is tied to the component instance, and React will destroy the component and its state when it is removed from the screen.
  • React updates state in an asynchronous manner, so updates are not applied immediately. Instead, they’re batched and applied at once after all event handlers have finished execution. Once the state is updated, React re-renders our component.

Choose State Structure

  • To keep state as minimal as possible, avoid redundant state variables that can be computed from existing variables.
  • Group related state variables into an object to keep them organized.
  • Avoid deeply nested state objects as they can be hard to update and maintain.
const [person, setPerson] = useState({firstName: "ganesh", lastName: "kumar"});
const [loading, setLoading] = useState(false);

Keep Components Pure

  • A pure function is one that always returns the same result given the same input. Pure functions should not modify objects/variables outside of the function.
  • A pure component should always return the same JSX given the same input.
  • React expects our function components to be pure for performance reasons. If the inputs are not changed react can skip re-rendering the component

Pure Component

let count = 0;

function Hello() {
  return <h1>Hello - {count}</h1>;
}

export default Hello;

Impure Component

let count = 0;

function Hello() {
  count++;
  return <h1>Hello - {count}</h1>;
}

export default Hello;

Strict Mode

  • StrictMode component is built-in component and doesn't have visual representation. Wraps root component
  • Strict mode helps us catch potential problems such as impure components. Starting from React 18, it is enabled by default. It renders our components twice in development mode to detect any potential side effects
  • The first render is used for detecting and reporting potential issues with the code
  • The second render to update the UI

Update Object Immutable

  • When updating objects or arrays, we should treat them as immutable/read-only objects. Instead of mutating them, we should create new objects or arrays to update the state.
  • Just like props we should treat state object as immutable/read-only
//create item
const [item, setItem] = useState({ title:  "Coffee", price:  10 });

//update item
setItem({...item, price: 20})

Update Nested Object Immutable

  • Spread operator does shallow copy only
const [customer, setCustomer] = useState({
	name: "Ganesh",
	address: {
		city: "Chennai"
		country: "IN"
	}
})
setCustomer({
	...customer,
	address: {
		...customer.address,
		city: "Bangalore"
	}
})

Update Arrays Immutable

//add
setTags[...tags, "new tag"];

//update
setTags(tags.map(tag => tag === "tag2" ? "tag2 updated": tag);

//remove
setTags(tags.filter(tag => tag !== "tag1");

Update Logic with Immer

  • Immer is a library that can help us update objects and arrays in a more concise and mutable way.
  • Install Immer
npm i immer@9.0.19
  • Import product
import produce from "immer"
  • Update logic
setBugs(produce(draft => {
	const bug = draft.find(bug => bug.id === 1);
	if(bug) bug.fixed = true;
}))

Sharing State between Components

  • To share state between components, we should lift the state up to the closest parent component and pass it down as props to child components.
  • The component that holds some state should be the one that updates it. If a child component needs to update some state, it should notify the parent component using a callback function passed down as a prop.