1. Responding to events

  2. State: a component’s memory

  3. Render and commit = no code sample
  4. State as a snapshot
  5. Queueing a series of state updates
  6. Updating objects in state
  7. Updating arrays in state

Why is mutating state not recommended in React? => https://react.dev/learn/updating-objects-in-state#why-is-mutating-state-not-recommended-in-react

  1. Responding to events

    • Built-in components like
    • To add an event handler, you will first define a function and then pass it as a prop to the appropriate JSX tag.
    • By convention, it is common to name event handlers as handle followed by the event name. You’ll often see onClick={handleClick}, onMouseEnter={handleMouseEnter}
    • Event handlers will also catch events from any children your component might have. We say that an event “bubbles” or “propagates” up the tree: it starts with where the event happened, and then goes up the tree.
    • All events propagate in React except onScroll, which only works on the JSX tag you attach it to.
    • Event handlers receive an event object as their only argument. By convention, it’s usually called e, which stands for “event”. You can use this object to read information about the event.
    • That event object also lets you stop the propagation. If you want to prevent an event from reaching parent components, you need to call e.stopPropagation() like this Button component does:
    • onClickCapture
    • e.preventDefault() prevents the default browser behavior for the few events that have it.
    • e.stopPropagation() stops the event handlers attached to the tags above from firing.
    • Event handlers must be passed, not called! onClick={handleClick}, not onClick={handleClick()}.
    • Event handlers are defined inside a component, so they can access props.
    • <button onClick={handleClick}> same as <button onClick={() => handleClick()}>
  2. State: a component’s memory

    • state is components memory
    • The useState Hook lets you declare a state variable. It takes the initial state and returns a pair of values: the current state, and a state setter function that lets you update it.
    • why not local varibale
      1. Local variables don’t persist between renders. When React renders this component a second time, it renders it from scratch—it doesn’t consider any changes to the local variables.
      2. Changes to local variables won’t trigger renders. React doesn’t realize it needs to render the component again with the new data.
    • To update a component with new data, two things need to happen:
      1. Retain the data between renders.
      2. Trigger React to render the component with new data (re-rendering).
  3. Render and commithttps://codesandbox.io/s/5vchpm?file=/App.js&utm_medium=sandpack

    • Before your components are displayed on the screen, they must be rendered by React.

      1. Triggering a render

        1. It’s the component’s initial render. - During the initial render, React will create the DOM nodes for

          ,

          , and three tags.

        2. The component’s (or one of its ancestors’) state has been updated. - During a re-render, React will calculate which of their properties, if any, have changed since the previous render. It won’t do anything with that information until the next step, the commit phase.

      2. Rendering the component

        • After you trigger a render, React calls your components to figure out what to display on screen. “Rendering” is React calling your components.
        • On initial render, React will call the root component.
        • For subsequent renders, React will call the function component whose state update triggered the render.
        • This process is recursive: if the updated component returns some other component, React will render that component next, and if that component also returns something, it will render that component next, and so on. The process will continue until there are no more nested components and React knows exactly what should be displayed on screen.
      3. Comitting to DOM

        1. For the initial render, React will use the appendChild() DOM API to put all the DOM nodes it has created on screen
        2. For re-renders, React will apply the minimal necessary operations (calculated while rendering!) to make the DOM match the latest rendering output.
        3. React only changes the DOM nodes if there’s a difference between renders. For example, here is a component that re-renders with different props passed from its parent every second. Notice how you can add some text into the , updating its value, but the text doesn’t disappear when the component re-renders:
  4. State as a snapshot

    • Unlike regular JavaScript variables, React state behaves more like a snapshot. Setting it does not change the state variable you already have, but instead triggers a re-render.
    • When React re-renders a component:
      1. React calls your function again.
      2. Your function returns a new JSX snapshot.
      3. React then updates the screen to match the snapshot your function returned.
    • current state of component is like closure it has current value
    • The state stored in React may have changed by the time the alert runs, but it was scheduled using a snapshot of the state at the time the user interacted with it!
    • A state variable’s value never changes within a render, even if its event handler’s code is asynchronous. Inside that render’s onClick, the value of number continues to be 0 even after setNumber(number + 5) was called.
          setNumber(0 + 5);
          setTimeout(() => {
          alert(0);
          }, 3000);
      
    • Variables and event handlers don’t “survive” re-renders. Every render has its own event handlers.
    • Event handlers created in the past have the state values from the render in which they were created.
  5. Queueing a series of state updates

    • setNumber(number + 5); (directly replacing value) = replaces value
    • setNumber (n => n + 1) (updater function) = takes previous value and adds 1 to it
    • State as a Snapshot explains why this is happening. Setting state requests a new re-render, but does not change it in the already running code. So score continues to be 0 right after you call setScore(score + 1).
            <button onClick={() => {
              setNumber(number + 1);
              setNumber(number + 1);
              setNumber(number + 1);
          }}>+3</button>
      
      • However, as you might recall from the previous section, each render’s state values are fixed, so the value of number inside the first render’s event handler is always 0, no matter how many times you call setNumber(1): . React waits until all code in the event handlers has run before processing your state updates. This is why the re-render only happens after all these setNumber() calls.
      • Batching - This lets you update multiple state variables—even from multiple components—without triggering too many re-renders. But this also means that the UI won’t be updated until after your event handler, and any code in it, completes. This behavior, also known as batching, makes your React app run much faster. It also avoids dealing with confusing “half-finished” renders where only some of the variables have been updated.
    • Updating the same state multiple times before the next render
      1. javascript <button onClick={() => { setNumber(n => n + 1); setNumber(n => n + 1); setNumber(n => n + 1); }}>+3</button>
      2. n => n + 1 is called an updater function. When you pass it to a state setter:
        1. React queues this function to be processed after all the other code in the event handler has run.
        2. During the next render, React goes through the queue and gives you the final updated state.
  6. Updating objects in state

    • So far you’ve been working with numbers, strings, and booleans. These kinds of JavaScript values are “immutable”, meaning unchangeable or “read-only”. You can trigger a re-render to replace a value:
    • State can hold any kind of JavaScript value, including objects. But you shouldn’t change objects and arrays that you hold in the React state directly. Instead, when you want to update an object and array, you need to create a new one (or make a copy of an existing one), and then update the state to use that copy.
    • Usually, you will use the ... spread syntax to copy objects and arrays that you want to change.
    • Mutation - only for Object and Array not for primitives like string, number ,boolean etc
    • mutation is you are changing content of objec or array
    • Instead of mutating them, you should always replace them.

            setPerson({
                ...person,
                email: e.target.value
            });
    
            // for nested object updation
    
            const nextArtwork = { ...person.artwork, city: 'New Delhi' };
            const nextPerson = { ...person, artwork: nextArtwork };
            setPerson(nextPerson);
    
            or
    
            setPerson({
                ...person, // Copy other fields
                artwork: { // but replace the artwork
                    ...person.artwork, // with the same one
                    city: 'New Delhi' // but in New Delhi!
                }
            });
    
    
    
            setStudent((prevState) => ({
                    ...prevState,
                    name: 'newName',
                    }));
    
    7. Updating arrays in state - Instead, every time you want to update an array, you’ll want to pass a new array to your state setting function by calling its non-mutating methods like filter() and map(). - ```javascript

        // to add element to end of array
        setArtists( // Replace the state
            [ // with a new array
                ...artists, // that contains all the old items
                { id: nextId++, name: name } // and one new item at the end
            ]
        );
    
        //to add element at start of array
    
            setArtists([
            { id: nextId++, name: name },
            ...artists // Put old items at the end
            ]);
    
        // insert any any position
    
            function handleClick() {
                const insertAt = 3; // Could be any index
                const nextArtists = [
                // Items before the insertion point:
                ...artists.slice(0, insertAt),
                // New item:
                { id: nextId++, name: name },
                // Items after the insertion point:
                ...artists.slice(insertAt)
                ];
                setArtists(nextArtists);
                setName('');
            }
    
        // reversing array or sorting
    
            function handleClick() {
                const nextList = [...list];
                nextList.reverse(); // use sort() or reverse()
                setList(nextList);
            }
    ```
    
    • Updating objects inside arrays
      • When updating nested state, you need to create copies from the point where you want to update, and all the way up to the top level.