Previously on

React Conf
When it happens
🔍
user interacting
async request
subscription
- State changes
- Parent's component render
- Context changes
- Hooks changes

React.memo()
Causes to:
Why do we care?
✋
🛑
🚀
const ChildComponent = React.memo(({
		filterData
	}) {
	console.log('child rendering ...')
	return < > ChildStuff < />
})
const ParentComponent = () => {
	const filterData = () => {
      // do something 
    }
    
	const handleClick = useCallback(filterData, [])
    
	return <ChildComponent filterData = {
		handleClick
	}
	/>
}https://www.insta.com/user-account?userId=34124 const { search } = useLocation();
 const queryParams = useMemo(() => new URLSearchParams(search),[search]);
 const closeUserDetailModal = useCallback(() => {
   const parameter = queryParams.get('userId');
    if (parameter) {
      queryParams.delete('userId');
    }
    history.replace({
      search: queryParams?.toString(),
    });
    refreshPage();
  }, [history, queryParams, refreshPage]);
  useEffect(() => {
    const userId = queryParams.get('userId');
    if (userId) {
      setState(() => ({ selectedBranch: Number(userId) }));
    }
  }, [queryParams]);const button = () => {
  let systemLocked = useContext(Loader);
  // The rest of your rendering logic
  return <FreezedComponent isSystemLocked={systemLocked} />;
}const button = () => {
  let appContextValue = useContext(AppContext);
  let systemLocked = appContextValue.systemLocked; // Your "loader"
  return <FreezedButton systemLocked={systemLocked} />
}
const FreezedButton = memo(({ systemLocked }) => {
  // The rest of your rendering logic
  return <ExpensiveTree isSystemLocked={systemLocked} />;
});const button = () => {
  let appContextValue = useContext(AppContext);
  let systemLocked = appContextValue.systemLocked; // Your "loader"
  return useMemo(() => {
    // The rest of your rendering logic
    return <ExpensiveTree isSystemLocked={systemLocked} />;
  }, [systemLocked])
}Memorization
App
//...
    return {
        swap: React.useCallback(swap, [updateValues, name, control]),
        move: React.useCallback(move, [updateValues, name, control]),
        prepend: React.useCallback(prepend, [updateValues, name, control]),
        append: React.useCallback(append, [updateValues, name, control]),
        remove: React.useCallback(remove, [updateValues, name, control]),
        insert: React.useCallback(insert, [updateValues, name, control]),
        update: React.useCallback(update, [updateValues, name, control]),
        replace: React.useCallback(replace, [updateValues, name, control]),
        fields: React.useMemo(
        () =>
            fields.map((field, index) => ({
            ...field,
            [keyName]: ids.current[index] || generateId(),
            })) as FieldArrayWithId<TFieldValues, TFieldArrayName, TKeyName>[],
        [fields, keyName],
    )💭
😵💫
useMemo === useCallback
memorization
overusing useMemo
solid understanding
figure out best practices
👋🏻
Khrystyna Landvytovych
FE Engineer, SoftServe
💊
Approve
Simplify 

Customize your hook
1. plain JavaScript object
2. value can be accessed, modified
3. should be persist
First step
🤓
// useState returns an array. Index zero is the current value
const ref = useState({ current: initialValue })[0]
useRef?
🤨
Recompute the memoized value only when one of the dependencies has changed
Shallow Compare
🧐
const shallowEquals = (prevDeps, currentDeps) => {
  if (!Array.isArray(prevDeps) || !Array.isArray(currentDeps)) {
    return false;
  }
  if (prevDeps.length !== currentDeps.length) {
    return false;
  }
 
  for(item of prevDeps) {
    if (!Object.is(prevDeps[item], currentDeps[item])) {
      return false;
    }
  }
  return true;
};
const useMyMemo = (create, dependencies) => {
  const val = useRef(create());
  const prevDependencies = useRef([]);
  if (!shallowEquals(dependencies, prevDependencies.current)) {
    val.current = create();
    prevDependencies.current = [...dependencies];
  }
  return val;
};# PRESENTING CODE
1
Customise useRef by useState
2
useMemo similar to useRef
4
What about useCallBack
3
Combine useRef with auto-update functionality
useCallback((e) => onClick(id, e.target.value), [onClick, id]);
// is equivalent to
useMemo(() => (e) => onClick(id, e.target.value), [onClick, id]);
Where we get wrong?
const App = () => {
  const [state, setState] = useState(1);
  return (
    <div className="App">
      <button onClick={
     	() => setState(state + 1)}> 
    		click to re-render {state}
      </button>
      <br />
      <Page />
    </div>
  );
};const Page = () => <Item />;
const PageMemoized = React.memo(Page);Only one way
const myMovieFilter = React.useCallback(film => {
  setMovies(allMovies => allMovies.filter(el => el.genre !== 'Horror'))
}, [])
// equals to 
const myMovieFilter = film => {
  setMovies(allMovies => allMovies.filter(el => el.genre !== 'Horror'))
}
const unnecessaryCallback = React.useCallback(myMovieFilter, [])Extra check for values
const myMovieFilter = React.useCallback(film => {
  setMovies(allMovies => allMovies.filter(el => el.genre !== 'Horror'))
}, [])
const MoviesList = ({ movies }) => {
  const content = useMemo(() => {
    const sortedMovies = orderBy(movies, 'name', sort);
    return sortedMovies.map((movie) => <Item movie={movie} key={movie.id} />);
  }, [movies, sort]);
  return content;
};Unnecessary with primitive values
Array sorting perf:  
2
Overall performance:  
8.300000004470348
Array filtering perf:  
0.8999999985098839
Overall performance:  
9.700000002980232
Array filtering perf:  
1.7999999970197678
Overall performance:  
16.5
Array sorting perf:  
53.89999999851😍
😦
😵
import React, { useState, useMemo } from "react";
const Child = ({ value }) => {
  console.log("Child re-renders", value.value);
  return <>{value.value}</>;
};
const App = () => {
  const [state, setState] = useState(1);
  const onClick = () => {
    setState(state + 1);
  };
  const memoValue = useMemo(() => ({ value: "I still render" }), []);
  return (
    <>
      <p>Child will re-render even if its value is memoized</p>
      <button onClick={onClick}>click here</button>
      
      <Child value={memoValue} />
    </>
  );
};
export default App;
if (!instanceRef.current) {
        instanceRef.current = createTableInstance<
          TData,
          TValue,
          TFilterFns,
          TSortingFns,
          TAggregationFns
        >(options, rerender)
      }
return instanceRef.currentUseRef 
is an answear
const button = () => {
  let appContextValue = useContext(AppContext);
  let systemLocked = appContextValue.systemLocked; // Your "loader"
  return <FreezedButton systemLocked={systemLocked} />
}
const FreezedButton = memo(({ systemLocked }) => {
  // The rest of your rendering logic
  return <ExpensiveTree isSystemLocked={systemLocked} />;
});Refactoring time ✨
const useIsSystemLocked = () => {
  const {
    data: { getSystemStatus } = { getSystemStatus: SystemStatus.Unlocked },
    networkStatus,
    refetch: refetchSystemStatusQuery,
  } = useQuery<SystemStatusQuery, SystemStatusQueryVariables>(systemStatusQuery);
  const systemLocked = isSystemLocked(getSystemStatus);
  const previousSystemLocked = usePrevious(systemLocked);
  return {
      previousSystemLocked,
      systemLocked,
    }
};Moral
Most of situations we can skip React.memo's friends
Make Performance optimizations with rensposibility.

Stay with 🇺🇦
@croftyland

Don't Forget React
By Khrystyna Landvytovych
Don't Forget React
- 599
 
   
   
  