How to escape from react ?

How to escape from react ?

escape hatches that let you “step outside” React and connect to external systems. like implementing video players, using browser apis etc.

refs

  • Component will remember the info but change wont trigger re renders. const ref = useRef(0); use ref by ref.current = 1;
  • ref is mutable and it can point to anything.
RefsState
useRef(initialValue) returns { current: initialValue }useState(initialValue) returns the current value of a state variable and a state setter function ([value, setValue])
Doesn’t trigger re-render when you change it.Triggers re-render when you change it.
Mutable—you can modify and update current’s value outside of the rendering process.”Immutable”—you must use the state setting function to modify state variables to queue a re-render.
You shouldn’t read (or write) the current value during rendering.You can read state at any time. However, each render has its own snapshot of state which does not change.

working of useRef


// This code is self explanatory
// Inside of React
function useRef(initialValue) {
  const [ref, unused] = useState({ current: initialValue });
  return ref;
}

When to use

  • Storing timeout IDs
  • Storing and manipulating DOM elements.
  • Storing other objects that aren’t necessary to calculate the JSX.

Best practice for useRef

  • use when woring with external systems or browser APIs
  • Don’t read or write ref.current during rendering.

Ref doesnt have any limitations of useState. updates are immediately applied to ref value.

DOM and refs

Usage

  1. import { useRef } from 'react';
  2. const myRef = useRef(null);
  3. <div ref={myRef}> <= pass the ref as the ref attribute of JSX tag.
  4. When react create DOM node for div , we can access that via myRef.current.[api call];

Aproaches to manage a list of refs using a ref callback

  1. Get a single ref to their parent element, and then use DOM manipulation methods like querySelectorAll to “find” the individual child nodes from it.
  2. pass a function to the ref attribute. This is called a ref callback.
// put a Map in ref.
 itemsRef.current = new Map();

{catList.map((cat) => (
            <li
              key={cat}
              ref={(node) => {
                const map = getMap();
                map.set(cat, node);

                return () => {
                  map.delete(cat);
                };
              }}
            >
              <img src={cat} />
            </li>
          ))}

Accessing another component’s DOM nodes

we can use this by passing ref as props . usecases includes css changes. To restrict exposed functionality use useImperativeHandle

useRef and rendering

All updates in react is in 2 phases

  1. During render
    1. Dont access refs
    2. refs with DOM will be empty, because its not created .
  2. During commit
    1. ref.current is set during commit
    2. if nodes in ref are updated , once nodes are updated in dom its updated in ref.
  • Access ref from event handlers or effects

if we want to update dom syncronusly use flushSync

flushSync(() => {
 setTodos([ ...todos, newTodo]);
});
listRef.current.lastChild.scrollIntoView();

Best practices

  • Avoid changing DOM nodes managed by React.
  • only use them when you have to “step outside React”.

Effects

Effects let you run some code after rendering so that you can synchronize your component with some system outside of React. In another words, Effects let you specify side effects that are caused by rendering itself, rather than by a particular event.

There is 2 type of logic in a comoponent.

  1. Rendering code
    • Must be pure.
  2. Event handlers
    • contain side effects.

Usage

import { useEffect } from 'react';

function MyComponent() {
  useEffect(() => {
    // Code here will run after *every* render
    return () => {
     // cleanup code
     // React will call your cleanup function each time before the Effect runs again, and one final time when the component unmounts (gets removed).
    };
  }[//add dependencies in here]);
  return <div />;
}
  • dependencies can have multiple values
  • if any dependency changes , react will re render.
  • if there is empty [] effect will run only on mount( when component appears)
  • we can provide ref(object returned by useRef) as a dependency if needed.
    • A mutable value like ref.current or things you read from it also can’t be a dependency.
  • Reactive variables(state,props,regular) can be added to dependencies.
  • A mutable value like location.pathname can’t be a dependency.
    • read and subscribe to an external mutable value with useSyncExternalStore

How to stop effect firing twice in development?

  • Do cleanup (effects firing twice shouldnt be a problem).
  • Using refs will do the trick but we need to fix any issues caused by effect firing twice by fixing the logic.

Use cases

  • Controlling non-React widgets
  • Subscribing to events
  • Triggering animations
  • Fetching data
  • Sending analytics

When Effects are not needed

  • Initializing the application
    • Only run once logic should be put out of components
  • Buying a product

read closure.

When not to use effect

If there is no external system involved (for example, if you want to update a component’s state when some props or state change), you shouldn’t need an Effect.

You don’t need Effects to ..

  • transform data for rendering./Cache expensive calculations (learn about Memoize and useMemo).
    • Do this in parent and pass data as props
  • handle user events
  • updating state based on props or state .

Check if the calculation is expensive by wraping the code to test inside console.time('filter array'); and console.timeEnd('filter array');

  • Resetting all state when a prop changes
    • Give key to component to clear state when component changes
  • Adjusting some state when a prop changes
    • Do this while rendering , no need to use useEffect
  • Share logic between event handlers

When you’re not sure whether some code should be in an Effect or in an event handler, ask yourself why this code needs to run. Use Effects only for code that should run because the component was displayed to the user

  • Send a POST request for form submission
  • Chains of computations
    • Triggering one effect from another effect is not adviced.
    • Doing this is very inefficient
    • Some times we can use this , iff we are syncing with another network with each computations.
  • Initialize the application
  • Notify parent components about state changes
    • Use event handler .
  • Pass data to the parent
    • When child components update the state of their parent components in Effects, the data flow becomes very difficult to trace. Since both the child and the parent need the same data, let the parent component fetch that data, and pass it down to the child instead.
  • Subscribing to an external store !
  • Fetch data
    • Possibility of race conditions
    • Use custom hook.

Lifecycle of Reactive Effects

Effect can only do two things:

  • to start synchronizing something.
    • re syncronisation will happend when dependency changes (react will check dependency every time after re render using Object.is).
  • to stop synchronizing it (call clean up function).

Effect’s lifecycle is different from a component’s lifecycle

  • An Effect describes how to synchronize an external system to the current props and state.

  • always focus on a single start/stop cycle at a time. It shouldn’t matter whether a component is mounting, updating, or unmounting. All you need to do is to describe how to start synchronization and how to stop it. If you do it well, your Effect will be resilient to being started and stopped as many times as it’s needed.

  • Each Effect in your code should represent a separate and independent synchronization process.

Separating Events from Effects

  • Event handlers run in response to specific interactions
  • Effects run whenever synchronization is needed

Reactive values and reactive logic

  • Props, state, and variables declared inside your component’s body are called reactive values.
    • Might change in a re-render
  • Logic within event handler is not reactive
    • Event handlers can read reactive values without “reacting” to their changes.
  • Logic inside Effects is reactive
    • if a rerender causes value to change , effects related to that will run.

Effect event (Experimental)

Use a special Hook called useEffectEvent to extract non-reactive logic out of your Effect

  • Effect Events are not reactive and must be omitted from dependencies.
  • Effect Events are triggered by you from Effects.
  • always declare Effect Events directly next to the Effects that use them
function ChatRoom({ roomId, theme }) {

  // onConnected is called an Effect Event. It’s a part of your Effect logic, but it behaves a lot more like an event handler
  const onConnected = useEffectEvent(() => {
    showNotification('Connected!', theme);
  });

  useEffect(()=>{
    // call onConnected here.
  });

}

Limitations

  • Only call them from inside Effects.
  • Never pass them to other components or Hooks.

Guide to remove effect dependencies

Dont suppress dependency linter (you might miss some bugs)

  • To remove a dependency, prove that it’s not a dependency
    • Reactive values include props and all variables and functions declared directly inside of your component.
  • To change the dependencies, change the surrounding code first.
  • Ask following
    • Should this code move to an event handler?
    • Is your Effect doing several unrelated things?
      • Each Effect should represent an independent synchronization process.
    • Are you reading some state to calculate the next state?
      • pass an updater function
    • Do you want to read a value without “reacting” to its changes?
      • useEffectEvent usages are
        • Wrapping an event handler from the props
        • Separating reactive and non-reactive code
    • Does some reactive value change unintentionally?
      • Object and function dependencies can make your Effect re-synchronize more often than you need.
      • Move static objects and functions outside your component
      • Move dynamic objects and functions inside your Effect
      • Read primitive values from objects (which is a prop)
        • Then change in object with same value wont cause the synchronization to happen. const { roomId, serverUrl } = options;
      • Calculate primitive values from functions (which is a prop)
        • const { roomId, serverUrl } = getOptions();
        • only works for pure functions

Custom Hooks

  • to reuse logic using custom hooks
  • hooks will use another hooks inside of it
  • Custom Hooks let you share stateful logic, not state itself.Each call to a Hook is completely independent from every other call to the same Hook.
  • custom Hooks need to be pure,it will re-run during every re-render of your component.
  • useEffectEvent can be used if we want to pass event handler as a props. this is to stop unnecessory re-render or in another words Wrap event handlers received by custom Hooks into Effect Events.

React naming conventions

  • React component names must start with a capital letter, like StatusBar
  • Hook names must start with use followed by a capital letter, like useState.
    • If your function doesn’t call any Hooks, avoid the use prefix

When to used custom hooks

  • if we want to isolate some common logic.
  • Avoid using custom “lifecycle” Hooks, eg: a custom useMount hook.

A good custom Hook makes the calling code more declarative by constraining what it does.

Wrapping your Effects in custom Hooks makes it easier to upgrade your code when better built-in solution for your use case become available.

read more on useSyncExternalStore

Advantage of custom hooks

  • You make the data flow to and from your Effects very explicit.
  • You let your components focus on the intent rather than on the exact implementation of your Effects.
  • When React adds new features, you can remove those Effects without changing any of your components.