Why hooks? The rules of hooks useRef, useState, useEffect, useMemo & useCallback Why we like Functional Components Pure functions, easier to reason about Don't have to worry about lifecycle methods Less boilerplate Easier to write tooling for - at this point, we've all kind of agreed that we like functional components more, for a bunch of reasons that aren't super relevant to this talk - but, they do have a major downside What's wrong with Functional Components They can't store state They can't trigger re-renders No lifecycle methods Rules of Hooks Only Call Hooks at the Top Level Only Call Hooks from React Functions Compiled with problems:
× ERROR
[eslint] src/slides/1 - useRef/RulesOfHooks.tsxLine 54:19: React Hook "useRef" is called conditionally. React Hooks must be called in the exact same order in every component render react-hooks/rules-of-hooks Search for the keywords to learn more about each error.
Rules of Hooks Only Call Hooks at the Top Level Always call hooks in the same order Only Call Hooks from React Functions A hook belongs to an instance of a component
Hooks store state in arrays inside closures A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment).
function AddItemForm ({ onSubmit }: Props ) {
const countRef = useRef (null )
const nameRef = useRef (null )
const handleAddItem = (event ) => {
event.preventDefault ()
onSubmit (nameRef.current ?.value , countRef.current ?.value )
}
return (
<form onSubmit ={handleAddItem} >
<input type ="number" ref ={countRef} />
<input ref ={nameRef} />
<button > Add</button >
</form >
)
}
function AddItemForm ({ onSubmit }: Props ) {
const countRef = useRef (null )
const nameRef = useRef (null )
const handleAddItem = (event ) => {
event.preventDefault ()
onSubmit (nameRef.current ?.value , countRef.current ?.value )
}
return (
<form onSubmit ={handleAddItem} >
<input type ="number" ref ={countRef} />
<input ref ={nameRef} />
<button > Add</button >
</form >
)
}
function AddItemForm ({ onSubmit }: Props ) {
const countRef = useRef (null )
const nameRef = useRef (null )
const handleAddItem = (event ) => {
event.preventDefault ()
onSubmit (nameRef.current ?.value , countRef.current ?.value )
}
return (
<form onSubmit ={handleAddItem} >
<input type ="number" ref ={countRef} />
<input ref ={nameRef} />
<button > Add</button >
</form >
)
}
function AddItemForm ({ onSubmit }: Props ) {
const countRef = useRef (null )
const nameRef = useRef (null )
const handleAddItem = (event ) => {
event.preventDefault ()
onSubmit (nameRef.current ?.value , countRef.current ?.value )
}
return (
<form onSubmit ={handleAddItem} >
<input type ="number" ref ={countRef} />
<input ref ={nameRef} />
<button > Add</button >
</form >
)
}
we can just add more useRefs, but it breaks our basic useRef implementation
const FakeReact = ( ) => {
...
let currentIndex = 0 ;
const refs = [];
function after ( ) {
currentIndex = 0 ;
}
return {
useRef (initialValue ) {
if (typeof refs[currentIndex] === 'undefined' ) {
refs[currentIndex] = { current : initialValue };
}
const ref = refs[currentIndex];
currentIndex++;
return ref;
}
}
}
function AddItemForm ({ onSubmit }: Props ) {
const countRef = useRef (null )
const nameRef = useRef (null )
const handleAddItem = (event ) => {
event.preventDefault ()
onSubmit (nameRef.current ?.value , countRef.current ?.value )
}
return (
<form onSubmit ={handleAddItem} >
<input type ="number" ref ={countRef} />
<input ref ={nameRef} />
<button > Add</button >
</form >
)
}
const FakeReact = ( ) => {
...
let currentIndex = 0 ;
const refs = [];
function after ( ) {
currentIndex = 0 ;
}
return {
useRef (initialValue ) {
if (typeof refs[currentIndex] === 'undefined' ) {
refs[currentIndex] = { current : initialValue };
}
const ref = refs[currentIndex];
currentIndex++;
return ref;
}
}
}
function AddItemForm ({ onSubmit }: Props ) {
const countRef = useRef (null )
const nameRef = useRef (null )
const handleAddItem = (event ) => {
event.preventDefault ()
onSubmit (nameRef.current ?.value , countRef.current ?.value )
}
return (
<form onSubmit ={handleAddItem} >
<input type ="number" ref ={countRef} />
<input ref ={nameRef} />
<button > Add</button >
</form >
)
}
const FakeReact = ( ) => {
...
let currentIndex = 0 ;
const refs = [];
function after ( ) {
currentIndex = 0 ;
}
return {
useRef (initialValue ) {
if (typeof refs[currentIndex] === 'undefined' ) {
refs[currentIndex] = { current : initialValue };
}
const ref = refs[currentIndex];
currentIndex++;
return ref;
}
}
}
function AddItemForm ({ onSubmit }: Props ) {
const countRef = useRef (null )
const nameRef = useRef (null )
const handleAddItem = (event ) => {
event.preventDefault ()
onSubmit (nameRef.current ?.value , countRef.current ?.value )
}
return (
<form onSubmit ={handleAddItem} >
<input type ="number" ref ={countRef} />
<input ref ={nameRef} />
<button > Add</button >
</form >
)
}
function AddItemForm ({ onSubmit }: Props ) {
const countRef = useRef (null )
const nameRef = useRef (null )
const handleAddItem = (event ) => {
event.preventDefault ()
onSubmit (nameRef.current ?.value , countRef.current ?.value )
}
return (
<form onSubmit ={handleAddItem} >
<input type ="number" ref ={countRef} />
<input ref ={nameRef} />
<button > Add</button >
</form >
)
}
const FakeReact = ( ) => {
...
let currentIndex = 0 ;
const refs = [];
function after ( ) {
currentIndex = 0 ;
}
return {
useRef (initialValue ) {
if (typeof refs[currentIndex] === 'undefined' ) {
refs[currentIndex] = { current : initialValue };
}
const ref = refs[currentIndex];
currentIndex++;
return ref;
}
}
}
function AddItemForm ({ onSubmit }: Props ) {
const countRef = useRef (null )
const nameRef = useRef (null )
const handleAddItem = (event ) => {
event.preventDefault ()
onSubmit (nameRef.current ?.value , countRef.current ?.value )
}
return (
<form onSubmit ={handleAddItem} >
<input type ="number" ref ={countRef} />
<input ref ={nameRef} />
<button > Add</button >
</form >
)
}
const FakeReact = ( ) => {
...
let currentIndex = 0 ;
const refs = [];
function after ( ) {
currentIndex = 0 ;
}
return {
useRef (initialValue ) {
if (typeof refs[currentIndex] === 'undefined' ) {
refs[currentIndex] = { current : initialValue };
}
const ref = refs[currentIndex];
currentIndex++;
return ref;
}
}
}
const FakeReact = ( ) => {
...
let currentIndex = 0 ;
const refs = [];
function after ( ) {
currentIndex = 0 ;
}
return {
useRef (initialValue ) {
if (typeof refs[currentIndex] === 'undefined' ) {
refs[currentIndex] = { current : initialValue };
}
const ref = refs[currentIndex];
currentIndex++;
return ref;
}
}
}
function AddItemForm ({ onSubmit }: Props ) {
const countRef = useRef (null )
const nameRef = useRef (null )
const handleAddItem = (event ) => {
event.preventDefault ()
onSubmit (nameRef.current ?.value , countRef.current ?.value )
}
return (
<form onSubmit ={handleAddItem} >
<input type ="number" ref ={countRef} />
<input ref ={nameRef} />
<button > Add</button >
</form >
)
}
const FakeReact = ( ) => {
...
let currentIndex = 0 ;
const refs = [];
function after ( ) {
currentIndex = 0 ;
}
return {
useRef (initialValue ) {
if (typeof refs[currentIndex] === 'undefined' ) {
refs[currentIndex] = { current : initialValue };
}
const ref = refs[currentIndex];
currentIndex++;
return ref;
}
}
}
const FakeReact = ( ) => {
...
let currentIndex = 0 ;
const refs = [];
function after ( ) {
currentIndex = 0 ;
}
return {
useRef (initialValue ) {
if (typeof refs[currentIndex] === 'undefined' ) {
refs[currentIndex] = { current : initialValue };
}
const ref = refs[currentIndex];
currentIndex++;
return ref;
}
}
}
function AddItemForm ({ onSubmit }: Props ) {
const countRef = useRef (null )
const nameRef = useRef (null )
const handleAddItem = (event ) => {
event.preventDefault ()
onSubmit (nameRef.current ?.value , countRef.current ?.value )
}
return (
<form onSubmit ={handleAddItem} >
<input type ="number" ref ={countRef} />
<input ref ={nameRef} />
<button > Add</button >
</form >
)
}
const FakeReact = ( ) => {
...
let currentIndex = 0 ;
const refs = [];
function after ( ) {
currentIndex = 0 ;
}
return {
useRef (initialValue ) {
if (typeof refs[currentIndex] === 'undefined' ) {
refs[currentIndex] = { current : initialValue };
}
const ref = refs[currentIndex];
currentIndex++;
return ref;
}
}
}
function AddItemForm ({ onSubmit }: Props ) {
const countRef = useRef (null )
const nameRef = useRef (null )
const handleAddItem = (event ) => {
event.preventDefault ()
onSubmit (nameRef.current ?.value , countRef.current ?.value )
}
return (
<form onSubmit ={handleAddItem} >
<input type ="number" ref ={countRef} />
<input ref ={nameRef} />
<button > Add</button >
</form >
)
}
const FakeReact = ( ) => {
...
let currentIndex = 0 ;
const refs = [];
function after ( ) {
currentIndex = 0 ;
}
return {
useRef (initialValue ) {
if (typeof refs[currentIndex] === 'undefined' ) {
refs[currentIndex] = { current : initialValue };
}
const ref = refs[currentIndex];
currentIndex++;
return ref;
}
}
}
function AddItemForm ({ onSubmit }: Props ) {
const countRef = useRef (null )
const nameRef = useRef (null )
const handleAddItem = (event ) => {
event.preventDefault ()
onSubmit (nameRef.current ?.value , countRef.current ?.value )
}
return (
<form onSubmit ={handleAddItem} >
<input type ="number" ref ={countRef} />
<input ref ={nameRef} />
<button > Add</button >
</form >
)
}
const FakeReact = ( ) => {
...
let currentIndex = 0 ;
const refs = [];
function after ( ) {
currentIndex = 0 ;
}
return {
useRef (initialValue ) {
if (typeof refs[currentIndex] === 'undefined' ) {
refs[currentIndex] = { current : initialValue };
}
const ref = refs[currentIndex];
currentIndex++;
return ref;
}
}
}
function AddItemForm ({ onSubmit }: Props ) {
const countRef = useRef (null )
const nameRef = useRef (null )
const handleAddItem = (event ) => {
event.preventDefault ()
onSubmit (nameRef.current ?.value , countRef.current ?.value )
}
return (
<form onSubmit ={handleAddItem} >
<input type ="number" ref ={countRef} />
<input ref ={nameRef} />
<button > Add</button >
</form >
)
}
const FakeReact = ( ) => {
...
let currentIndex = 0 ;
const refs = [];
function after ( ) {
currentIndex = 0 ;
}
return {
useRef (initialValue ) {
if (typeof refs[currentIndex] === 'undefined' ) {
refs[currentIndex] = { current : initialValue };
}
const ref = refs[currentIndex];
currentIndex++;
return ref;
}
}
}
function AddItemForm ({ onSubmit }: Props ) {
const countRef = useRef (null )
const nameRef = useRef (null )
const handleAddItem = (event ) => {
event.preventDefault ()
onSubmit (nameRef.current ?.value , countRef.current ?.value )
}
return (
<form onSubmit ={handleAddItem} >
<input type ="number" ref ={countRef} />
<input ref ={nameRef} />
<button > Add</button >
</form >
)
}
const FakeReact = ( ) => {
...
let currentIndex = 0 ;
const refs = [];
function after ( ) {
currentIndex = 0 ;
}
return {
useRef (initialValue ) {
if (typeof refs[currentIndex] === 'undefined' ) {
refs[currentIndex] = { current : initialValue };
}
const ref = refs[currentIndex];
currentIndex++;
return ref;
}
}
}
const FakeReact = ( ) => {
...
let currentIndex = 0 ;
const refs = [];
function after ( ) {
currentIndex = 0 ;
}
return {
useRef (initialValue ) {
if (typeof refs[currentIndex] === 'undefined' ) {
refs[currentIndex] = { current : initialValue };
}
const ref = refs[currentIndex];
currentIndex++;
return ref;
}
}
}
function AddItemForm ({ onSubmit }: Props ) {
const countRef = useRef (null )
const nameRef = useRef (null )
const handleAddItem = (event ) => {
event.preventDefault ()
onSubmit (nameRef.current ?.value , countRef.current ?.value )
}
return (
<form onSubmit ={handleAddItem} >
<input type ="number" ref ={countRef} />
<input ref ={nameRef} />
<button > Add</button >
</form >
)
}
const FakeReact = ( ) => {
...
let currentIndex = 0 ;
const refs = [];
function after ( ) {
currentIndex = 0 ;
}
return {
useRef (initialValue ) {
if (typeof refs[currentIndex] === 'undefined' ) {
refs[currentIndex] = { current : initialValue };
}
const ref = refs[currentIndex];
currentIndex++;
return ref;
}
}
}
function AddItemForm ({ onSubmit }: Props ) {
const countRef = useRef (null )
const nameRef = useRef (null )
const handleAddItem = (event ) => {
event.preventDefault ()
onSubmit (nameRef.current ?.value , countRef.current ?.value )
}
return (
<form onSubmit ={handleAddItem} >
<input type ="number" ref ={countRef} />
<input ref ={nameRef} />
<button > Add</button >
</form >
)
}
const FakeReact = ( ) => {
...
let currentIndex = 0 ;
const refs = [];
function after ( ) {
currentIndex = 0 ;
}
return {
useRef (initialValue ) {
if (typeof refs[currentIndex] === 'undefined' ) {
refs[currentIndex] = { current : initialValue };
}
const ref = refs[currentIndex];
currentIndex++;
return ref;
}
}
}
function AddItemForm ({ onSubmit }: Props ) {
const countRef = useRef (null )
const nameRef = useRef (null )
const handleAddItem = (event ) => {
event.preventDefault ()
onSubmit (nameRef.current ?.value , countRef.current ?.value )
}
return (
<form onSubmit ={handleAddItem} >
<input type ="number" ref ={countRef} />
<input ref ={nameRef} />
<button > Add</button >
</form >
)
}
const FakeReact = ( ) => {
...
let currentIndex = 0 ;
const refs = [];
function after ( ) {
currentIndex = 0 ;
}
return {
useRef (initialValue ) {
if (typeof refs[currentIndex] === 'undefined' ) {
refs[currentIndex] = { current : initialValue };
}
const ref = refs[currentIndex];
currentIndex++;
return ref;
}
}
}
const FakeReact = ( ) => {
...
let currentIndex = 0 ;
const refs = [];
function after ( ) {
currentIndex = 0 ;
}
return {
useRef (initialValue ) {
if (typeof refs[currentIndex] === 'undefined' ) {
refs[currentIndex] = { current : initialValue };
}
const ref = refs[currentIndex];
currentIndex++;
return ref;
}
}
}
function AddItemForm ({ onSubmit }: Props ) {
const countRef = useRef (null )
const nameRef = useRef (null )
const handleAddItem = (event ) => {
event.preventDefault ()
onSubmit (nameRef.current ?.value , countRef.current ?.value )
}
return (
<form onSubmit ={handleAddItem} >
<input type ="number" ref ={countRef} />
<input ref ={nameRef} />
<button > Add</button >
</form >
)
}
const FakeReact = ( ) => {
...
let currentIndex = 0 ;
const refs = [];
function after ( ) {
currentIndex = 0 ;
}
return {
useRef (initialValue ) {
if (typeof refs[currentIndex] === 'undefined' ) {
refs[currentIndex] = { current : initialValue };
}
const ref = refs[currentIndex];
currentIndex++;
return ref;
}
}
}
function AddItemForm ({ onSubmit }: Props ) {
const countRef = useRef (null )
const nameRef = useRef (null )
const handleAddItem = (event ) => {
event.preventDefault ()
onSubmit (nameRef.current ?.value , countRef.current ?.value )
}
return (
<form onSubmit ={handleAddItem} >
<input type ="number" ref ={countRef} />
<input ref ={nameRef} />
<button > Add</button >
</form >
)
}
currentIndex 1
refs
current: null
current: null
const FakeReact = ( ) => {
...
let currentIndex = 0 ;
const refs = [];
function after ( ) {
currentIndex = 0 ;
}
return {
useRef (initialValue ) {
if (typeof refs[currentIndex] === 'undefined' ) {
refs[currentIndex] = { current : initialValue };
}
const ref = refs[currentIndex];
currentIndex++;
return ref;
}
}
}
function AddItemForm ({ onSubmit }: Props ) {
const countRef = useRef (null )
const nameRef = useRef (null )
const handleAddItem = (event ) => {
event.preventDefault ()
onSubmit (nameRef.current ?.value , countRef.current ?.value )
}
return (
<form onSubmit ={handleAddItem} >
<input type ="number" ref ={countRef} />
<input ref ={nameRef} />
<button > Add</button >
</form >
)
}
currentIndex 1
refs
current: null
current: null
const FakeReact = ( ) => {
...
let currentIndex = 0 ;
const refs = [];
function after ( ) {
currentIndex = 0 ;
}
return {
useRef (initialValue ) {
if (typeof refs[currentIndex] === 'undefined' ) {
refs[currentIndex] = { current : initialValue };
}
const ref = refs[currentIndex];
currentIndex++;
return ref;
}
}
}
function AddItemForm ({ onSubmit }: Props ) {
const countRef = useRef (null )
const nameRef = useRef (null )
const handleAddItem = (event ) => {
event.preventDefault ()
onSubmit (nameRef.current ?.value , countRef.current ?.value )
}
return (
<form onSubmit ={handleAddItem} >
<input type ="number" ref ={countRef} />
<input ref ={nameRef} />
<button > Add</button >
</form >
)
}
currentIndex 1
refs
current: null
current: null
const FakeReact = ( ) => {
...
let currentIndex = 0 ;
const refs = [];
function after ( ) {
currentIndex = 0 ;
}
return {
useRef (initialValue ) {
if (typeof refs[currentIndex] === 'undefined' ) {
refs[currentIndex] = { current : initialValue };
}
const ref = refs[currentIndex];
currentIndex++;
return ref;
}
}
}
function AddItemForm ({ onSubmit }: Props ) {
const countRef = useRef (null )
const nameRef = useRef (null )
const handleAddItem = (event ) => {
event.preventDefault ()
onSubmit (nameRef.current ?.value , countRef.current ?.value )
}
return (
<form onSubmit ={handleAddItem} >
<input type ="number" ref ={countRef} />
<input ref ={nameRef} />
<button > Add</button >
</form >
)
}
currentIndex 1
refs
current: null
current: null
const FakeReact = ( ) => {
...
let currentIndex = 0 ;
const refs = [];
function after ( ) {
currentIndex = 0 ;
}
return {
useRef (initialValue ) {
if (typeof refs[currentIndex] === 'undefined' ) {
refs[currentIndex] = { current : initialValue };
}
const ref = refs[currentIndex];
currentIndex++;
return ref;
}
}
}
const FakeReact = ( ) => {
...
let currentIndex = 0 ;
const refs = [];
function after ( ) {
currentIndex = 0 ;
}
return {
useRef (initialValue ) {
if (typeof refs[currentIndex] === 'undefined' ) {
refs[currentIndex] = { current : initialValue };
}
const ref = refs[currentIndex];
currentIndex++;
return ref;
}
}
}
function AddItemForm ({ onSubmit }: Props ) {
const countRef = useRef (null )
const nameRef = useRef (null )
const handleAddItem = (event ) => {
event.preventDefault ()
onSubmit (nameRef.current ?.value , countRef.current ?.value )
}
return (
<form onSubmit ={handleAddItem} >
<input type ="number" ref ={countRef} />
<input ref ={nameRef} />
<button > Add</button >
</form >
)
}
currentIndex 2
refs
current: null
current: null
const FakeReact = ( ) => {
...
let currentIndex = 0 ;
const refs = [];
function after ( ) {
currentIndex = 0 ;
}
return {
useRef (initialValue ) {
if (typeof refs[currentIndex] === 'undefined' ) {
refs[currentIndex] = { current : initialValue };
}
const ref = refs[currentIndex];
currentIndex++;
return ref;
}
}
}
function AddItemForm ({ onSubmit }: Props ) {
const countRef = useRef (null )
const nameRef = useRef (null )
const handleAddItem = (event ) => {
event.preventDefault ()
onSubmit (nameRef.current ?.value , countRef.current ?.value )
}
return (
<form onSubmit ={handleAddItem} >
<input type ="number" ref ={countRef} />
<input ref ={nameRef} />
<button > Add</button >
</form >
)
}
currentIndex 2
refs
current: null
current: null
const FakeReact = ( ) => {
...
let currentIndex = 0 ;
const refs = [];
function after ( ) {
currentIndex = 0 ;
}
return {
useRef (initialValue ) {
if (typeof refs[currentIndex] === 'undefined' ) {
refs[currentIndex] = { current : initialValue };
}
const ref = refs[currentIndex];
currentIndex++;
return ref;
}
}
}
function AddItemForm ({ onSubmit }: Props ) {
const countRef = useRef (null )
const nameRef = useRef (null )
const handleAddItem = (event ) => {
event.preventDefault ()
onSubmit (nameRef.current ?.value , countRef.current ?.value )
}
return (
<form onSubmit ={handleAddItem} >
<input type ="number" ref ={countRef} />
<input ref ={nameRef} />
<button > Add</button >
</form >
)
}
function AddItemForm ({ onSubmit }: Props ) {
const countRef = useRef (null )
const nameRef = useRef (null )
const handleAddItem = (event ) => {
event.preventDefault ()
onSubmit (nameRef.current ?.value , countRef.current ?.value )
}
return (
<form onSubmit ={handleAddItem} >
<input type ="number" ref ={countRef} />
<input ref ={nameRef} />
<button > Add</button >
</form >
)
}
function AddItemForm ({ onSubmit }: Props ) {
const countRef = useRef (null )
const nameRef = useRef (null )
const handleAddItem = (event ) => {
event.preventDefault ()
onSubmit (nameRef.current ?.value , countRef.current ?.value )
}
return (
<form onSubmit ={handleAddItem} >
<input type ="number" ref ={countRef} />
<input ref ={nameRef} />
<button > Add</button >
</form >
)
}
currentIndex 2
refs
current: null
current: null
const FakeReact = ( ) => {
...
let currentIndex = 0 ;
const refs = [];
function after ( ) {
currentIndex = 0 ;
}
return {
useRef (initialValue ) {
if (typeof refs[currentIndex] === 'undefined' ) {
refs[currentIndex] = { current : initialValue };
}
const ref = refs[currentIndex];
currentIndex++;
return ref;
}
}
}
function AddItemForm ({ onSubmit }: Props ) {
const countRef = useRef (null )
const nameRef = useRef (null )
const handleAddItem = (event ) => {
event.preventDefault ()
onSubmit (nameRef.current ?.value , countRef.current ?.value )
}
return (
<form onSubmit ={handleAddItem} >
<input type ="number" ref ={countRef} />
<input ref ={nameRef} />
<button > Add</button >
</form >
)
}
currentIndex 2
refs
current: <input />
current: <input />
const FakeReact = ( ) => {
...
let currentIndex = 0 ;
const refs = [];
function after ( ) {
currentIndex = 0 ;
}
return {
useRef (initialValue ) {
if (typeof refs[currentIndex] === 'undefined' ) {
refs[currentIndex] = { current : initialValue };
}
const ref = refs[currentIndex];
currentIndex++;
return ref;
}
}
}
const FakeReact = ( ) => {
...
let currentIndex = 0 ;
const refs = [];
function after ( ) {
currentIndex = 0 ;
}
return {
useRef (initialValue ) {
if (typeof refs[currentIndex] === 'undefined' ) {
refs[currentIndex] = { current : initialValue };
}
const ref = refs[currentIndex];
currentIndex++;
return ref;
}
}
}
function AddItemForm ({ onSubmit }: Props ) {
const countRef = useRef (null )
const nameRef = useRef (null )
const handleAddItem = (event ) => {
event.preventDefault ()
onSubmit (nameRef.current ?.value , countRef.current ?.value )
}
return (
<form onSubmit ={handleAddItem} >
<input type ="number" ref ={countRef} />
<input ref ={nameRef} />
<button > Add</button >
</form >
)
}
currentIndex 2
refs
current: <input />
current: <input />
const FakeReact = ( ) => {
...
let currentIndex = 0 ;
const refs = [];
function after ( ) {
currentIndex = 0 ;
}
return {
useRef (initialValue ) {
if (typeof refs[currentIndex] === 'undefined' ) {
refs[currentIndex] = { current : initialValue };
}
const ref = refs[currentIndex];
currentIndex++;
return ref;
}
}
}
function AddItemForm ({ onSubmit }: Props ) {
const countRef = useRef (null )
const nameRef = useRef (null )
const handleAddItem = (event ) => {
event.preventDefault ()
onSubmit (nameRef.current ?.value , countRef.current ?.value )
}
return (
<form onSubmit ={handleAddItem} >
<input type ="number" ref ={countRef} />
<input ref ={nameRef} />
<button > Add</button >
</form >
)
}
currentIndex 0
refs
current: <input />
current: <input />
const FakeReact = ( ) => {
...
let currentIndex = 0 ;
const refs = [];
function after ( ) {
currentIndex = 0 ;
}
return {
useRef (initialValue ) {
if (typeof refs[currentIndex] === 'undefined' ) {
refs[currentIndex] = { current : initialValue };
}
const ref = refs[currentIndex];
currentIndex++;
return ref;
}
}
}
function AddItemForm ({ onSubmit }: Props ) {
const countRef = useRef (null )
const nameRef = useRef (null )
const handleAddItem = (event ) => {
event.preventDefault ()
onSubmit (nameRef.current ?.value , countRef.current ?.value )
}
return (
<form onSubmit ={handleAddItem} >
<input type ="number" ref ={countRef} />
<input ref ={nameRef} />
<button > Add</button >
</form >
)
}
currentIndex 0
refs
current: <input />
current: <input />
const FakeReact = ( ) => {
...
let currentIndex = 0 ;
const refs = [];
function after ( ) {
currentIndex = 0 ;
}
return {
useRef (initialValue ) {
if (typeof refs[currentIndex] === 'undefined' ) {
refs[currentIndex] = { current : initialValue };
}
const ref = refs[currentIndex];
currentIndex++;
return ref;
}
}
}
function AddItemForm ({ onSubmit }: Props ) {
const countRef = useRef (null )
const nameRef = useRef (null )
const handleAddItem = (event ) => {
event.preventDefault ()
onSubmit (nameRef.current ?.value , countRef.current ?.value )
}
return (
<form onSubmit ={handleAddItem} >
<input type ="number" ref ={countRef} />
<input ref ={nameRef} />
<button > Add</button >
</form >
)
}
currentIndex 0
refs
current: <input />
current: <input />
const FakeReact = ( ) => {
...
let currentIndex = 0 ;
const refs = [];
function after ( ) {
currentIndex = 0 ;
}
return {
useRef (initialValue ) {
if (typeof refs[currentIndex] === 'undefined' ) {
refs[currentIndex] = { current : initialValue };
}
const ref = refs[currentIndex];
currentIndex++;
return ref;
}
}
}
function AddItemForm ({ onSubmit }: Props ) {
const countRef = useRef (null )
const nameRef = useRef (null )
const handleAddItem = (event ) => {
event.preventDefault ()
onSubmit (nameRef.current ?.value , countRef.current ?.value )
}
return (
<form onSubmit ={handleAddItem} >
<input type ="number" ref ={countRef} />
<input ref ={nameRef} />
<button > Add</button >
</form >
)
}
function AddItemForm ({ onSubmit }: Props ) {
const countRef = useRef (null )
const nameRef = useRef (null )
const handleAddItem = (event ) => {
event.preventDefault ()
onSubmit (nameRef.current ?.value , countRef.current ?.value )
}
return (
<form onSubmit ={handleAddItem} >
<input type ="number" ref ={countRef} />
<input ref ={nameRef} />
<button > Add</button >
</form >
)
}
currentIndex 0
refs
current: <input />
current: <input />
const FakeReact = ( ) => {
...
let currentIndex = 0 ;
const refs = [];
function after ( ) {
currentIndex = 0 ;
}
return {
useRef (initialValue ) {
if (typeof refs[currentIndex] === 'undefined' ) {
refs[currentIndex] = { current : initialValue };
}
const ref = refs[currentIndex];
currentIndex++;
return ref;
}
}
}
function AddItemForm ({ onSubmit }: Props ) {
const countRef = useRef (null )
const nameRef = useRef (null )
const handleAddItem = (event ) => {
event.preventDefault ()
onSubmit (nameRef.current ?.value , countRef.current ?.value )
}
return (
<form onSubmit ={handleAddItem} >
<input type ="number" ref ={countRef} />
<input ref ={nameRef} />
<button > Add</button >
</form >
)
}
Hooks store state in arrays inside closures
function Inventory ( ) {
const [inventory, setInventory] = useState ([])
const addItem = (name, count ) => {
setInventory (
addItemToInventory (inventory, name, count)
)
}
return (
<>
<AddItemForm onSubmit ={addItem} />
<ItemList items ={inventory} />
</>
)
}
function Inventory ( ) {
const [inventory, setInventory] = useState ([])
const addItem = (name, count ) => {
setInventory (
addItemToInventory (inventory, name, count)
)
}
return (
<>
<AddItemForm onSubmit ={addItem} />
<ItemList items ={inventory} />
</>
)
}
function Inventory ( ) {
const [inventory, setInventory] = useState ([])
const addItem = (name, count ) => {
setInventory (
addItemToInventory (inventory, name, count)
)
}
return (
<>
<AddItemForm onSubmit ={addItem} />
<ItemList items ={inventory} />
</>
)
}
function Inventory ( ) {
const [inventory, setInventory] = useState ([])
const addItem = (name, count ) => {
setInventory (
addItemToInventory (inventory, name, count)
)
}
return (
<>
<AddItemForm onSubmit ={addItem} />
<ItemList items ={inventory} />
</>
)
}
function Inventory ( ) {
const [inventory, setInventory] = useState ([])
const addItem = (name, count ) => {
setInventory (
addItemToInventory (inventory, name, count)
)
}
return (
<>
<AddItemForm onSubmit ={addItem} />
<ItemList items ={inventory} />
</>
)
}
function Inventory ( ) {
const [inventory, setInventory] = useState ([])
const addItem = (name, count ) => {
setInventory (
addItemToInventory (inventory, name, count)
)
}
return (
<>
<AddItemForm onSubmit ={addItem} />
<ItemList items ={inventory} />
</>
)
}
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
function Inventory ( ) {
const [inventory, setInventory] = useState ([])
const addItem = (name, count ) => {
setInventory (
addItemToInventory (inventory, name, count)
)
}
return (
<>
<AddItemForm onSubmit ={addItem} />
<ItemList items ={inventory} />
</>
)
}
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
function Inventory ( ) {
const [inventory, setInventory] = useState ([])
const addItem = (name, count ) => {
setInventory (
addItemToInventory (inventory, name, count)
)
}
return (
<>
<AddItemForm onSubmit ={addItem} />
<ItemList items ={inventory} />
</>
)
}
currentIndex 0
runComponent ❌
states [ ]
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
function Inventory ( ) {
const [inventory, setInventory] = useState ([])
const addItem = (name, count ) => {
setInventory (
addItemToInventory (inventory, name, count)
)
}
return (
<>
<AddItemForm onSubmit ={addItem} />
<ItemList items ={inventory} />
</>
)
}
function Inventory ( ) {
const [inventory, setInventory] = useState ([])
const addItem = (name, count ) => {
setInventory (
addItemToInventory (inventory, name, count)
)
}
return (
<>
<AddItemForm onSubmit ={addItem} />
<ItemList items ={inventory} />
</>
)
}
currentIndex 0
runComponent ❌
states [ ]
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
function Inventory ( ) {
const [inventory, setInventory] = useState ([])
const addItem = (name, count ) => {
setInventory (
addItemToInventory (inventory, name, count)
)
}
return (
<>
<AddItemForm onSubmit ={addItem} />
<ItemList items ={inventory} />
</>
)
}
currentIndex 0
runComponent ❌
states [ ]
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
function Inventory ( ) {
const [inventory, setInventory] = useState ([])
const addItem = (name, count ) => {
setInventory (
addItemToInventory (inventory, name, count)
)
}
return (
<>
<AddItemForm onSubmit ={addItem} />
<ItemList items ={inventory} />
</>
)
}
currentIndex 0
runComponent ❌
states [[ ] ]
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
function Inventory ( ) {
const [inventory, setInventory] = useState ([])
const addItem = (name, count ) => {
setInventory (
addItemToInventory (inventory, name, count)
)
}
return (
<>
<AddItemForm onSubmit ={addItem} />
<ItemList items ={inventory} />
</>
)
}
currentIndex 0
runComponent ❌
states [[ ] ]
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
function Inventory ( ) {
const [inventory, setInventory] = useState ([])
const addItem = (name, count ) => {
setInventory (
addItemToInventory (inventory, name, count)
)
}
return (
<>
<AddItemForm onSubmit ={addItem} />
<ItemList items ={inventory} />
</>
)
}
currentIndex 0
runComponent ❌
states [[ ] ]
setterIndex 0
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
function Inventory ( ) {
const [inventory, setInventory] = useState ([])
const addItem = (name, count ) => {
setInventory (
addItemToInventory (inventory, name, count)
)
}
return (
<>
<AddItemForm onSubmit ={addItem} />
<ItemList items ={inventory} />
</>
)
}
currentIndex 0
runComponent ❌ 🔑
states [[ ] 🔑 ]
setterIndex 0
setter 🔑
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
function Inventory ( ) {
const [inventory, setInventory] = useState ([])
const addItem = (name, count ) => {
setInventory (
addItemToInventory (inventory, name, count)
)
}
return (
<>
<AddItemForm onSubmit ={addItem} />
<ItemList items ={inventory} />
</>
)
}
currentIndex 1
runComponent ❌ 🔑
states [[ ] 🔑 ]
setterIndex 0
setter 🔑
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
function Inventory ( ) {
const [inventory, setInventory] = useState ([])
const addItem = (name, count ) => {
setInventory (
addItemToInventory (inventory, name, count)
)
}
return (
<>
<AddItemForm onSubmit ={addItem} />
<ItemList items ={inventory} />
</>
)
}
function Inventory ( ) {
const [inventory, setInventory] = useState ([])
const addItem = (name, count ) => {
setInventory (
addItemToInventory (inventory, name, count)
)
}
return (
<>
<AddItemForm onSubmit ={addItem} />
<ItemList items ={inventory} />
</>
)
}
function Inventory ( ) {
const [inventory, setInventory] = useState ([])
const addItem = (name, count ) => {
setInventory (
addItemToInventory (inventory, name, count)
)
}
return (
<>
<AddItemForm onSubmit ={addItem} />
<ItemList items ={inventory} />
</>
)
}
function Inventory ( ) {
const [inventory, setInventory] = useState ([])
const addItem = (name, count ) => {
setInventory (
addItemToInventory (inventory, name, count)
)
}
return (
<>
<AddItemForm onSubmit ={addItem} />
<ItemList items ={inventory} />
</>
)
}
currentIndex 1
runComponent ❌ 🔑
states [[ ] 🔑 ]
setInventory 🔑
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
function Inventory ( ) {
const [inventory, setInventory] = useState ([])
const addItem = (name, count ) => {
setInventory (
addItemToInventory (inventory, name, count)
)
}
return (
<>
<AddItemForm onSubmit ={addItem} />
<ItemList items ={inventory} />
</>
)
}
currentIndex 1
runComponent ❌ 🔑
states [[ ] 🔑 ]
setInventory 🔑
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
function Inventory ( ) {
const [inventory, setInventory] = useState ([])
const addItem = (name, count ) => {
setInventory (
addItemToInventory (inventory, name, count)
)
}
return (
<>
<AddItemForm onSubmit ={addItem} />
<ItemList items ={inventory} />
</>
)
}
currentIndex 1
runComponent ❌ 🔑
states [[ ] 🔑 ]
setInventory 🔑
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
function Inventory ( ) {
const [inventory, setInventory] = useState ([])
const addItem = (name, count ) => {
setInventory (
addItemToInventory (inventory, name, count)
)
}
return (
<>
<AddItemForm onSubmit ={addItem} />
<ItemList items ={inventory} />
</>
)
}
currentIndex 1
runComponent ❌
states [[ ] ]
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
function Inventory ( ) {
const [inventory, setInventory] = useState ([])
const addItem = (name, count ) => {
setInventory (
addItemToInventory (inventory, name, count)
)
}
return (
<>
<AddItemForm onSubmit ={addItem} />
<ItemList items ={inventory} />
</>
)
}
currentIndex 0
runComponent ❌
states [[ ] ]
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
function Inventory ( ) {
const [inventory, setInventory] = useState ([])
const addItem = (name, count ) => {
setInventory (
addItemToInventory (inventory, name, count)
)
}
return (
<>
<AddItemForm onSubmit ={addItem} />
<ItemList items ={inventory} />
</>
)
}
currentIndex 0
runComponent ❌
states [[ ] ]
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
function Inventory ( ) {
const [inventory, setInventory] = useState ([])
const addItem = (name, count ) => {
setInventory (
addItemToInventory (inventory, name, count)
)
}
return (
<>
<AddItemForm onSubmit ={addItem} />
<ItemList items ={inventory} />
</>
)
}
currentIndex 0
runComponent ❌
states [[ ] ]
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
function Inventory ( ) {
const [inventory, setInventory] = useState ([])
const addItem = (name, count ) => {
setInventory (
addItemToInventory (inventory, name, count)
)
}
return (
<>
<AddItemForm onSubmit ={addItem} />
<ItemList items ={inventory} />
</>
)
}
currentIndex 0
runComponent ❌
states [[ ] ]
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
function Inventory ( ) {
const [inventory, setInventory] = useState ([])
const addItem = (name, count ) => {
setInventory (
addItemToInventory (inventory, name, count)
)
}
return (
<>
<AddItemForm onSubmit ={addItem} />
<ItemList items ={inventory} />
</>
)
}
currentIndex 0
runComponent ❌
states [[ ] ]
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
function Inventory ( ) {
const [inventory, setInventory] = useState ([])
const addItem = (name, count ) => {
setInventory (
addItemToInventory (inventory, name, count)
)
}
return (
<>
<AddItemForm onSubmit ={addItem} />
<ItemList items ={inventory} />
</>
)
}
currentIndex 0
runComponent ❌ 🔑
states [[ ] 🔑 ]
setInventory 🔑
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
function Inventory ( ) {
const [inventory, setInventory] = useState ([])
const addItem = (name, count ) => {
setInventory (
addItemToInventory (inventory, name, count)
)
}
return (
<>
<AddItemForm onSubmit ={addItem} />
<ItemList items ={inventory} />
</>
)
}
currentIndex 0
runComponent ❌
states [[ ] ]
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
function Inventory ( ) {
const [inventory, setInventory] = useState ([])
const addItem = (name, count ) => {
setInventory (
addItemToInventory (inventory, name, count)
)
}
return (
<>
<AddItemForm onSubmit ={addItem} />
<ItemList items ={inventory} />
</>
)
}
currentIndex 0
runComponent ❌
states [[🍎 ] ]
setterIndex 0
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
function Inventory ( ) {
const [inventory, setInventory] = useState ([])
const addItem = (name, count ) => {
setInventory (
addItemToInventory (inventory, name, count)
)
}
return (
<>
<AddItemForm onSubmit ={addItem} />
<ItemList items ={inventory} />
</>
)
}
currentIndex 0
runComponent ✅
states [[🍎 ] ]
setterIndex 0
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
function Inventory ( ) {
const [inventory, setInventory] = useState ([])
const addItem = (name, count ) => {
setInventory (
addItemToInventory (inventory, name, count)
)
}
return (
<>
<AddItemForm onSubmit ={addItem} />
<ItemList items ={inventory} />
</>
)
}
currentIndex 0
runComponent ✅
states [[🍎 ] ]
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
function Inventory ( ) {
const [inventory, setInventory] = useState ([])
const addItem = (name, count ) => {
setInventory (
addItemToInventory (inventory, name, count)
)
}
return (
<>
<AddItemForm onSubmit ={addItem} />
<ItemList items ={inventory} />
</>
)
}
currentIndex 0
runComponent ✅
states [[🍎 ] ]
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
function Inventory ( ) {
const [inventory, setInventory] = useState ([])
const addItem = (name, count ) => {
setInventory (
addItemToInventory (inventory, name, count)
)
}
return (
<>
<AddItemForm onSubmit ={addItem} />
<ItemList items ={inventory} />
</>
)
}
currentIndex 0
runComponent ❌
states [[🍎 ] ]
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
function Inventory ( ) {
const [inventory, setInventory] = useState ([])
const addItem = (name, count ) => {
setInventory (
addItemToInventory (inventory, name, count)
)
}
return (
<>
<AddItemForm onSubmit ={addItem} />
<ItemList items ={inventory} />
</>
)
}
currentIndex 0
runComponent ❌
states [[🍎 ] ]
const FakeReact = ( ) => {
let currentIndex = 0
const states = []
let runComponent = false
function after ( ) {
currentIndex = 0
}
return {
onSubmit (element, handler ) {
element.addEventListener ("submit" , (event ) => {
handler (event)
if (runComponent) {
runComponent = false
Component (props)
}
})
},
useState (initialValue ) {
if (typeof states[currentIndex] === "undefined" ) {
states[currentIndex] = initialValue
}
const value = states[currentIndex]
const setterIndex = currentIndex
const setter = (value ) => {
if (value !== states[setterIndex]) {
states[setterIndex] = value
runComponent = true
}
}
currentIndex++
return [value, setter]
},
}
}
function Inventory ( ) {
const [inventory, setInventory] = useState ([])
const addItem = (name, count ) => {
setInventory (
addItemToInventory (inventory, name, count)
)
}
return (
<>
<AddItemForm onSubmit ={addItem} />
<ItemList items ={inventory} />
</>
)
}
function Inventory ( ) {
const [inventory, setInventory] = useState ([])
const addItem = (name, count ) => {
setInventory (
addItemToInventory (inventory, name, count)
)
}
return (
<>
<AddItemForm onSubmit ={addItem} />
<ItemList items ={inventory} />
</>
)
}
function Inventory ( ) {
const [inventory, setInventory] = useState ([])
const addItem = (name, count ) => {
setInventory (
addItemToInventory (inventory, name, count)
)
}
return (
<>
<AddItemForm onSubmit ={addItem} />
<ItemList items ={inventory} />
</>
)
}
currentIndex 0
runComponent ❌ 🔑
states [[🍎 ] 🔑 ]
setInventory 🔑
useState Stores state in an array in a closure Re-renders the component when the state changes 🍎 x55 🌰 x3 🍖 x108 💎 x1 🍄 x27 🐟 x18
export function ItemList ({ items, setItems }: Props ) {
window .addEventListener ("keydown" , (event ) => {
if (!event.key .match (/^[1-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
setItems (
items.map ((item, index ) =>
index === indexToUpdate ?
{ ...item, count : --item.count } :
item
)
)
})
return (...)
}
export function ItemList ({ items, setItems }: Props ) {
window .addEventListener ("keydown" , (event ) => {
if (!event.key .match (/^[1-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
setItems (
items.map ((item, index ) =>
index === indexToUpdate ?
{ ...item, count : --item.count } :
item
)
)
})
return (...)
}
export function ItemList ({ items, setItems }: Props ) {
window .addEventListener ("keydown" , (event ) => {
if (!event.key .match (/^[1-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
setItems (
items.map ((item, index ) =>
index === indexToUpdate ?
{ ...item, count : --item.count } :
item
)
)
})
return (...)
}
export function ItemList ({ items, setItems }: Props ) {
window .addEventListener ("keydown" , (event ) => {
if (!event.key .match (/^[1-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
setItems (
items.map ((item, index ) =>
index === indexToUpdate ?
{ ...item, count : --item.count } :
item
)
)
})
return (...)
}
export function ItemList ({ items, setItems }: Props ) {
window .addEventListener ("keydown" , (event ) => {
if (!event.key .match (/^[1-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
setItems (
items.map ((item, index ) =>
index === indexToUpdate ?
{ ...item, count : --item.count } :
item
)
)
})
return (...)
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
effect : what we want to happendependencies : manage stale closurescleanup function : called before effect re-run
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
const FakeReact = ( ) => {
let currentIndex = 0
let effects = []
function after ( ) {
effects.forEach ((effect ) => {
const needsCleanup = dependenciesChanged (effect) || isUnmounting ()
if (needsCleanup && effect.cleanup ) {
effect.cleanup ()
}
})
effects = effects.map ((effect ) => {
if (!effect.deps || !effect.prevDeps || dependenciesChanged (effect)) {
return {
prevDeps : effect.deps ,
cleanup : effect.callback (),
}
}
return effect
})
currentIndex = 0 ;
}
function dependenciesChanged (effect ) {
if (!effect.prevDeps ) {
return false
}
return effect.deps .some ((dep, index ) => dep !== effect.prevDeps ?.[index])
}
return {
useEffect (callback, deps ) {
if (typeof effects[currentIndex] === "undefined" ) {
effects[currentIndex] = { callback, deps }
} else {
effects[currentIndex] = {
...effects[currentIndex],
callback,
deps,
}
}
currentIndex++;
}
}
}
function ItemList ({ items, setItems } ) {
useEffect (
() => {
const onKeyDown = (event ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
const itemToUpdate = itemsToShow[indexToUpdate]
setItems (
items.map ((i ) => (i === item ? { ...i, count : --i.count } : i))
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
},
[items, setItems]
)
return (...)
}
Dependency arrays Effects run at least once No dependency array - run on every render Empty dependency array - run once Use useEffect for native event handlers setTimeout/setInterval/requestAnimationFrame making HTTP calls interacting with 3rd party libraries Effects are an escape hatch from the React paradigm. Sort by name Sort by count 🍎 x55 🌰 x3 🍖 x108 💎 x1 🍄 x27 🐟 x18
function ItemList ({ items } ) {
const [sortedItems, setSortedItems] = useState (items);
const [sortBy, setSortBy] = useState ();
useEffect (() => {
if (sortBy) {
setSortedItems (items.sort (sortFunction (sortBy)))
} else {
setSortedItems (items)
}
},
[
items,
sortBy,
]);
const handleSort = (sortBy: keyof Item ) => {
setSortBy (sortBy);
};
useEffect (() => {
const onKeyDown = (event: KeyboardEvent ) => {
if (!event.key .match (/^[0-9]$/ )) return ;
const indexToUpdate = Number .parseInt (event.key ) - 1 ;
const itemToUpdate = sortedItems[indexToUpdate];
setSortedItems (
sortedItems.map ((i ) => (i === itemToUpdate ? { ...i, count : --i.count } : i))
);
};
window .addEventListener ("keydown" , onKeyDown);
return () => window .removeEventListener ("keydown" , onKeyDown);
}, [sortedItems]);
return (
<>
<button onClick ={() => handleSort("name")}>Sort by name</button >
<button onClick ={() => handleSort("count")}>Sort by count</button >
<ol >
{sortedItems.map((item) => (
<ListItem key ={item.name} item ={item} />
))}
</ol >
</>
);
}
function ItemList ({ items } ) {
const [sortedItems, setSortedItems] = useState (items);
const [sortBy, setSortBy] = useState ();
useEffect (() => {
if (sortBy) {
setSortedItems (items.sort (sortFunction (sortBy)))
} else {
setSortedItems (items)
}
},
[
items,
sortBy,
]);
const handleSort = (sortBy: keyof Item ) => {
setSortBy (sortBy);
};
useEffect (() => {
const onKeyDown = (event: KeyboardEvent ) => {
if (!event.key .match (/^[0-9]$/ )) return ;
const indexToUpdate = Number .parseInt (event.key ) - 1 ;
const itemToUpdate = sortedItems[indexToUpdate];
setSortedItems (
sortedItems.map ((i ) => (i === itemToUpdate ? { ...i, count : --i.count } : i))
);
};
window .addEventListener ("keydown" , onKeyDown);
return () => window .removeEventListener ("keydown" , onKeyDown);
}, [sortedItems]);
return (
<>
<button onClick ={() => handleSort("name")}>Sort by name</button >
<button onClick ={() => handleSort("count")}>Sort by count</button >
<ol >
{sortedItems.map((item) => (
<ListItem key ={item.name} item ={item} />
))}
</ol >
</>
);
}
function ItemList ({ items } ) {
const [sortedItems, setSortedItems] = useState (items);
const [sortBy, setSortBy] = useState ();
useEffect (() => {
if (sortBy) {
setSortedItems (items.sort (sortFunction (sortBy)))
} else {
setSortedItems (items)
}
},
[
items,
sortBy,
]);
const handleSort = (sortBy: keyof Item ) => {
setSortBy (sortBy);
};
useEffect (() => {
const onKeyDown = (event: KeyboardEvent ) => {
if (!event.key .match (/^[0-9]$/ )) return ;
const indexToUpdate = Number .parseInt (event.key ) - 1 ;
const itemToUpdate = sortedItems[indexToUpdate];
setSortedItems (
sortedItems.map ((i ) => (i === itemToUpdate ? { ...i, count : --i.count } : i))
);
};
window .addEventListener ("keydown" , onKeyDown);
return () => window .removeEventListener ("keydown" , onKeyDown);
}, [sortedItems]);
return (
<>
<button onClick ={() => handleSort("name")}>Sort by name</button >
<button onClick ={() => handleSort("count")}>Sort by count</button >
<ol >
{sortedItems.map((item) => (
<ListItem key ={item.name} item ={item} />
))}
</ol >
</>
);
}
❌
Don't use effects to transform data If you can calculate some information from the component’s props or its existing state variables during rendering, you should not put that information into that component’s state.
function ItemList ({ items, setItems } ) {
const [sortBy, setSortBy] = useState ();
const sortedItems = sortBy ? items.sort (sortFunction (sortBy)) : items;
useEffect (() => {
const onKeyDown = (event: KeyboardEvent ) => {
if (!event.key .match (/^[0-9]$/ )) return ;
const indexToUpdate = Number .parseInt (event.key ) - 1 ;
const itemToUpdate = sortedItems[indexToUpdate];
setItems (sortedItems.map ((i ) => (i === itemToUpdate ? { ...i, count : --i.count } : i)));
};
window .addEventListener ("keydown" , onKeyDown);
return () => window .removeEventListener ("keydown" , onKeyDown);
}, [sortedItems]);
return (
<>
<button onClick ={() => setSortBy("name")}>Sort by name</button >
<button onClick ={() => setSortBy("count")}>Sort by count</button >
<ol >
{itemsToShow.map((item) => (
<ListItem
key ={item.name}
item ={item}
/>
))}
</ol >
</>
);
}
function ItemList ({ items, setItems } ) {
const [sortBy, setSortBy] = useState ();
const sortedItems = sortBy ? items.sort (sortFunction (sortBy)) : items;
useEffect (() => {
const onKeyDown = (event: KeyboardEvent ) => {
if (!event.key .match (/^[0-9]$/ )) return ;
const indexToUpdate = Number .parseInt (event.key ) - 1 ;
const itemToUpdate = sortedItems[indexToUpdate];
setItems (sortedItems.map ((i ) => (i === itemToUpdate ? { ...i, count : --i.count } : i)));
};
window .addEventListener ("keydown" , onKeyDown);
return () => window .removeEventListener ("keydown" , onKeyDown);
}, [sortedItems]);
return (
<>
<button onClick ={() => setSortBy("name")}>Sort by name</button >
<button onClick ={() => setSortBy("count")}>Sort by count</button >
<ol >
{itemsToShow.map((item) => (
<ListItem
key ={item.name}
item ={item}
/>
))}
</ol >
</>
);
}
function ItemList ({ items, setItems } ) {
const [sortBy, setSortBy] = useState ();
const sortedItems = sortBy ? items.sort (sortFunction (sortBy)) : items;
useEffect (() => {
const onKeyDown = (event: KeyboardEvent ) => {
if (!event.key .match (/^[0-9]$/ )) return ;
const indexToUpdate = Number .parseInt (event.key ) - 1 ;
const itemToUpdate = sortedItems[indexToUpdate];
setItems (sortedItems.map ((i ) => (i === itemToUpdate ? { ...i, count : --i.count } : i)));
};
window .addEventListener ("keydown" , onKeyDown);
return () => window .removeEventListener ("keydown" , onKeyDown);
}, [sortedItems]);
return (
<>
<button onClick ={() => setSortBy("name")}>Sort by name</button >
<button onClick ={() => setSortBy("count")}>Sort by count</button >
<ol >
{itemsToShow.map((item) => (
<ListItem
key ={item.name}
item ={item}
/>
))}
</ol >
</>
);
}
But what if my calculation is really expensive? useMemo memoise a value ie only recalculate if it changes
const sortedItems = sortBy
? items.sort (sortFunction (sortBy))
: items;
const sortedItems = useMemo (
() => sortBy
? items.sort (sortFunction (sortBy))
: items,
[items, sortBy]
);
const sortedItems = useMemo (
() => sortBy
? items.sort (sortFunction (sortBy))
: items,
[items, sortBy]
);
const sortedItems = useMemo (
() => sortBy
? items.sort (sortFunction (sortBy))
: items,
[items, sortBy]
);
const sortedItems = useMemo (
() => sortBy
? items.sort (sortFunction (sortBy))
: items,
[items, sortBy]
);
const sortedItems = useMemo (
() => sortBy
? items.sort (sortFunction (sortBy))
: items,
[items, sortBy]
);
Sort by name Sort by count 🍎 x55 🌰 x3 🍖 x108 💎 x1 🍄 x27 🐟 x18
<ol>
{sortedItems.map ((item ) => (
<li key ={item.name} >
<button onClick ={...} >
{item.name} {item.count}
</button >
</li >
))}
</ol>
<ol>
{sortedItems.map ((item ) => (
<li key ={item.name} >
<button onClick ={...} >
{item.name} {item.count}
</button >
</li >
))}
</ol>
useEffect (() => {
const onKeyDown = (event: KeyboardEvent ) => {
if (!event.key .match (/^[0-9]$/ )) return
const indexToUpdate = Number .parseInt (event.key ) - 1
setItems (
sortedItems.map ((item, index ) =>
index === indexToUpdate ? { ...item, count : --item.count } : item
)
)
}
window .addEventListener ("keydown" , onKeyDown)
return () => window .removeEventListener ("keydown" , onKeyDown)
}, [sortedItems, setItems])
function ItemList ({ items, setItems }: Props ) {
const [sortBy, setSortBy] = useState<keyof Item | undefined >();
const [filter, setFilter] = useState ("" );
const itemsToShow = useMemo (...);
const consumeItem = (item: Item ) => {
setItems (items.map ((i ) => (i === item ? { ...i, count : --i.count } : i)));
};
useEffect (
() => {
const onKeyDown = (event: KeyboardEvent ) => {
if (!event.key .match (/^[0-9]$/ )) return ;
const indexToUpdate = Number .parseInt (event.key ) - 1 ;
const itemToUpdate = sortedItems[indexToUpdate];
consumeItem (itemToUpdate);
};
window .addEventListener ("keydown" , onKeyDown);
return () => window .removeEventListener ("keydown" , onKeyDown);
},
[
sortedItems,
setItems,
consumeItem,
]
);
return (
<>
<input onChange ={(event) => setFilter(event.target.value)} />
<button onClick ={() => setSortBy("name")}>Sort by name</button >
<button onClick ={() => setSortBy("count")}>Sort by count</button >
<ol >
{itemsToShow.map((item) => (
<ListItem
key ={item.name}
onClick ={() => consumeItem(item)}
item={item}
/>
))}
</ol >
</>
);
}
function ItemList ({ items, setItems }: Props ) {
const [sortBy, setSortBy] = useState<keyof Item | undefined >();
const [filter, setFilter] = useState ("" );
const itemsToShow = useMemo (...);
const consumeItem = (item: Item ) => {
setItems (items.map ((i ) => (i === item ? { ...i, count : --i.count } : i)));
};
useEffect (
() => {
const onKeyDown = (event: KeyboardEvent ) => {
if (!event.key .match (/^[0-9]$/ )) return ;
const indexToUpdate = Number .parseInt (event.key ) - 1 ;
const itemToUpdate = sortedItems[indexToUpdate];
consumeItem (itemToUpdate);
};
window .addEventListener ("keydown" , onKeyDown);
return () => window .removeEventListener ("keydown" , onKeyDown);
},
[
sortedItems,
setItems,
consumeItem,
]
);
return (
<>
<input onChange ={(event) => setFilter(event.target.value)} />
<button onClick ={() => setSortBy("name")}>Sort by name</button >
<button onClick ={() => setSortBy("count")}>Sort by count</button >
<ol >
{itemsToShow.map((item) => (
<ListItem
key ={item.name}
onClick ={() => consumeItem(item)}
item={item}
/>
))}
</ol >
</>
);
}
function ItemList ({ items, setItems }: Props ) {
const [sortBy, setSortBy] = useState<keyof Item | undefined >();
const [filter, setFilter] = useState ("" );
const itemsToShow = useMemo (...);
const consumeItem = (item: Item ) => {
setItems (items.map ((i ) => (i === item ? { ...i, count : --i.count } : i)));
};
useEffect (
() => {
const onKeyDown = (event: KeyboardEvent ) => {
if (!event.key .match (/^[0-9]$/ )) return ;
const indexToUpdate = Number .parseInt (event.key ) - 1 ;
const itemToUpdate = sortedItems[indexToUpdate];
consumeItem (itemToUpdate);
};
window .addEventListener ("keydown" , onKeyDown);
return () => window .removeEventListener ("keydown" , onKeyDown);
},
[
sortedItems,
setItems,
consumeItem,
]
);
return (
<>
<input onChange ={(event) => setFilter(event.target.value)} />
<button onClick ={() => setSortBy("name")}>Sort by name</button >
<button onClick ={() => setSortBy("count")}>Sort by count</button >
<ol >
{itemsToShow.map((item) => (
<ListItem
key ={item.name}
onClick ={() => consumeItem(item)}
item={item}
/>
))}
</ol >
</>
);
}
function ItemList ({ items, setItems }: Props ) {
const [sortBy, setSortBy] = useState<keyof Item | undefined >();
const [filter, setFilter] = useState ("" );
const itemsToShow = useMemo (...);
const consumeItem = (item: Item ) => {
setItems (items.map ((i ) => (i === item ? { ...i, count : --i.count } : i)));
};
useEffect (
() => {
const onKeyDown = (event: KeyboardEvent ) => {
if (!event.key .match (/^[0-9]$/ )) return ;
const indexToUpdate = Number .parseInt (event.key ) - 1 ;
const itemToUpdate = sortedItems[indexToUpdate];
consumeItem (itemToUpdate);
};
window .addEventListener ("keydown" , onKeyDown);
return () => window .removeEventListener ("keydown" , onKeyDown);
},
[
sortedItems,
setItems,
consumeItem,
]
);
return (
<>
<input onChange ={(event) => setFilter(event.target.value)} />
<button onClick ={() => setSortBy("name")}>Sort by name</button >
<button onClick ={() => setSortBy("count")}>Sort by count</button >
<ol >
{itemsToShow.map((item) => (
<ListItem
key ={item.name}
onClick ={() => consumeItem(item)}
item={item}
/>
))}
</ol >
</>
);
}
The 'consumeItem' function makes the dependencies of useEffect Hook (at line 533) change on every render. Move it inside the useEffect callback. Alternatively, wrap the definition of 'consumeItem' in its own useCallback() Hook.
eslint(react-hooks/exhaustive-deps )
const consumeItem : (item: Item ) => void
View Problem (Alt+F8) Quick Fix... (Ctrl+.)
function ItemList ({ items, setItems }: Props ) {
const [sortBy, setSortBy] = useState<keyof Item | undefined >();
const [filter, setFilter] = useState ("" );
const itemsToShow = useMemo (...);
const consumeItem = (item: Item ) => {
setItems (items.map ((i ) => (i === item ? { ...i, count : --i.count } : i)));
};
useEffect (
() => {
const onKeyDown = (event: KeyboardEvent ) => {
if (!event.key .match (/^[0-9]$/ )) return ;
const indexToUpdate = Number .parseInt (event.key ) - 1 ;
const itemToUpdate = sortedItems[indexToUpdate];
consumeItem (itemToUpdate);
};
window .addEventListener ("keydown" , onKeyDown);
return () => window .removeEventListener ("keydown" , onKeyDown);
},
[
sortedItems,
setItems,
consumeItem,
]
);
return (
<>
<input onChange ={(event) => setFilter(event.target.value)} />
<button onClick ={() => setSortBy("name")}>Sort by name</button >
<button onClick ={() => setSortBy("count")}>Sort by count</button >
<ol >
{itemsToShow.map((item) => (
<ListItem
key ={item.name}
onClick ={() => consumeItem(item)}
item={item}
/>
))}
</ol >
</>
);
}
const consumeItem = useMemo (
() => (item: Item ) => {
setItems (
items.map (
(i ) => (i === item ? { ...i, count : --i.count } : i)
)
)
},
[items, setItems]
)
const consumeItem = useMemo (
() => (item: Item ) => {
setItems (
items.map (
(i ) => (i === item ? { ...i, count : --i.count } : i)
)
)
},
[items, setItems]
)
const consumeItem = useMemo (
() => (item: Item ) => {
setItems (
items.map (
(i ) => (i === item ? { ...i, count : --i.count } : i)
)
)
},
[items, setItems]
)
const consumeItem = useCallback (
(item: Item ) => {
setItems (
items.map (
(i ) => (i === item ? { ...i, count : --i.count } : i)
)
)
},
[items, setItems]
)
const consumeItem = useCallback (
(item: Item ) => {
setItems (
items.map (
(i ) => (i === item ? { ...i, count : --i.count } : i)
)
)
},
[items, setItems]
)
What have we learnt? Hooks store state in arrays in closures useRef does nothing else useState triggers re-renders useEffect is an escape hatch useMemo & useCallback memoise things @ErinJZimmer