REACT 4, useMemo(), useReducer(), ReactJs scaling and useRef(()=>{}) Dom manipulation.

  • 1

  • 1

  • 1

useMemo(function, dependencies) is a React Hook that caches the return value of a function between re-renders.

const memoized = useMemo(
  () => memoize(depend),
  [depend]
);

A useMemo() function will be re-called only if one of its dependencies changes.

chevron-rightuseMemo() render examplehashtag

We import an array of objects as a prop with 2 useState().

import TodoList from './components/Externals';

import { createTodos } from './components/External1';
const todos = createTodos();

const [tab, setTab] = useState('all');
const [isDark, setIsDark] = useState(false);

<div>
  <button onClick={() => setTab('all')} />
  <button  onClick={() => setTab('active')} />
  <button onClick={() => setTab('completed')} />
</div>

<input
  type="checkbox"
  checked={isDark}
  onChange={e => setIsDark(e.target.checked)}
/>

<TodoList
  todos={todos}
  tab={tab}
  theme={isDark ? 'bg-warning' : 'bg-success text-white'}
/>

We useMemo() a slow imported function using 2 props, any theme useState() changes will re-render the parent component but won't re-call the useMemo() function.

import { filterTodos } from './External1'

function Todolist({ todos, theme, tab }) {

  const visibleTodos = useMemo(
    () => filterTodos(todos, tab),
    [todos, tab]
  );

  return (
    <div className={theme}>
      <p>Note: filterTodos is artificially slowed down!</p>
      <ul>
        {visibleTodos.map(todo => (
          <li key={todo.id}>
            {todo.completed ?
              <s>{todo.text}</s> :
              todo.text
            }
          </li>
        ))}
      </ul>
    </div>
  );
}

The useMemo() function is a delayed function that filters the array object to be rendered

export function filterTodos(todos, tab) {

  let startTime = performance.now();
  
  while (performance.now() - startTime < 500) {
    // Do nothing for 500 ms to emulate extremely slow code
  }

  return todos.filter(todo => {
    if (tab === 'all') {
      return true;
    } else if (tab === 'active') {
      return !todo.completed;
    } else if (tab === 'completed') {
      return todo.completed;
    }
  });
}
slow button useMemo() change and fast checkbox

The useRef() React Hook

The useRef() lets us reference a value that’s not needed for rendering

Contrary to useState(), useRef() changes won't re-render the page and its new value will be immediately available between different functions (unlike useState() which has to render it first).

chevron-rightDifference in updating useRef() and useState()hashtag

In this example, we show the useRef() value using a handler function.

Returned useRef() and useState() values

useRef() is stored in React and won't need any setter function because it always returns the same object.

useRef() is used to communicate with external API, timeID variables, and DOM manipulation, if rendered It won't update its value.

On inputs, you can render the useState() input AND a useRef().current value.

Don't useRef() on a javascript expression, its value won't update.

The same useRef() created inside repeated components won't interfere with each other.

chevron-rightIndipendent useRef() on repeated components and debounced buttonshashtag

An useRef() can't be initialized inside a normal function, only on a component.

Multiple components can useRef() independently from each other.

We clearTimeout() onClick() to debounce the button, to start its timeout() only after the button stops being clicked.

useRef() callback function and DOM manipulation

We useRef() to access the React Node JSX elements.

Accessing a JSX Node element

The ref attribute can contain a callback function, it uses the DOM as an argument, and it triggers on render.

Callback function on useState() render

The callback function ref argument can fill an useRef() array.

The ref attribute can't be assigned to Node elements on loops or javascript expressions.

We create a Map object of Node elements using ref callback function.

chevron-rightref callback function on looped Node elementshashtag

We create an array of 20 image objects and a getMap() function for the ref.

We use Node IDs from the ref map object and the map.get() for the scrollIntoView() method.

We use a new ref callback function to loop through each rendered <li> element, and we set the ref map object with key/value pairs of Images ID and Node element.

We can't pass a children ref from its parent component.

The Js querySelector() works in ReactJs, but it's better to use the useRef() hook on DOM elements.

Its mutable reference values persist and can be updated at any time without affecting component output or triggering re-renders.

A parent component can pass a useRef() hook to a children component as a prop, allowing the parent to access the updated DOM value from the children.

We use React.useImperativeHandle to customize the current value of a useRef() object and expose methods to its parent component.

These methods can return other useRef() or useState() values, allowing us to create an interface for editing the useRef() object from the parent component.

If the useRef() value gets updated on the children components, an event is needed to access it.

If you need more data to be shared between components check scale-up ReactJs.

The forwardRef() API opts for receiving the rep prop as the second argument into the child component.

Each React update includes a render (when it calls its function components) and a commit (where it applies the changes).

Ref isn't defined during the first render and will be null when no Node has been created yet. During commit ref is first set to null and then gets updated with the Node DOM element.

Updating a DOM element won't immediately update its ref Node element, DOM methods won't have the updated ref value either.

We use a flushSynch() call to wrap the update DOM function, so both can update synchronously.

chevron-rightFlushSynch() to scrollIntoView of updated DOM listhashtag

We set an array of objects, the ref for the <ul> node, and the <ul> and input useState().

We render the array as <li> elements, the ref is set on the <ul> but we can access its children using ref property .children and .childNode.

On input, we create a new object to push to the <ul> DOM.

Without flushSync() the ref DOM method would have scrolled at #20, instead of the new element.

Scroll onClick() without and then with Flushsynch()

ref shouldn't be used to edit the DOM, limit it to elements that aren't updated by React.

We can trigger the play() and pause() DOM method on a <video> Node ref.

We can create conditional ref attributes, using flushSync() to keep the ref condition updated.

chevron-rightscollIntoView() DOM method on conditional red attributehashtag

We create an array of image objects, we set the ref, the useState(), and the index (condition) flushSync() function.

We render the image array and set the conditional ref attribute on the Node element with ID matching the useState() index (that's why we need flushSync())

The moment a new Node element gets the ref attribute it will be scrollIntoView().

Scrolling onClick() using ref attributes and DOM methods

The Node element ref can receive a DOM method while in a different component, using forwardRef().

Last updated