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.
useMemo() render example
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;
}
});
}
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).
Difference in updating useRef() and useState()
In this example, we show the useRef() value using a handler function.

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.
Indipendent useRef() on repeated components and debounced buttons
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.

The ref attribute can contain a callback function, it uses the DOM as an argument, and it triggers on 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.
ref callback function on looped Node elements
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 can access and modify the DOM useRef() from both the parent and sibling components.
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.
Even if set in a useRef() object both useRef() and useState() follow their own render rules.
Any React.useImperativeHandle useState(), passed as a prop from the sibling component, will have a delayed value. We need a local useState() updated with ref.current values.
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.
FlushSynch() to scrollIntoView of updated DOM list
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.

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.
scollIntoView() DOM method on conditional red attribute
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().

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