# React(Native) developer for GoodDollar 1. What’s wrong with the logging in the following component ? How to make it correct and optimized according to the React Hooks’ rules ? ``` const App = () => { const [clicksCount, setClicksCount] = useState(0) // some handlers could modify clicksCount // console.log(clicksCount) return ( // some JSX which calls handlers on certain interactions ); } ``` ``` const App = () => { const [clicksCount, setClicksCount] = useState(0) // some handlers could modify clicksCount // useEffect(() => { console.log(clicksCount) }, [clicksCount]) return ( // some JSX which calls handlers on certain interactions ); } ``` 2. What’s wrong with the following optimization attempt ? How is the logic broken and why ? How can you optimize this component correctly ? Does it require optimization at all ? ``` const App = () => { const [clicksCount, setClicksCount] = useState(0) // added: const increaseClicksCount = useCallback(() => setClicksCount(clicksCount + 1), []) return ( <button // before: onClick={() => setClicksCount(clicksCount + 1)} onClick={increaseClicksCount} > ); } ``` ``` const App = () => { const [clicksCount, setClicksCount] = useState(0) const increaseClicksCount = () => setClicksCount(clicksCount + 1) return ( <button // before: onClick={() => setClicksCount(clicksCount + 1)} onClick={increaseClicksCount} > ); } ``` 3. What are 2 things missing in useEffect to make code more robust, correct, performant ? ``` const App = () => { const [appState, setAppState] = useState('active') useEffect(() => { const onFocus = () => setAppState('active') const onBlur = () => setAppState('inactive') window.addEventListener('focus', onFocus) window.addEventListener('blur', onBlur) }) return ( <p> App state: <code>{appState}</code>. </p> ); } ``` ``` const App = () => { const [appState, setAppState] = useState('active') useEffect(() => { const onFocus = () => setAppState('active') const onBlur = () => setAppState('inactive') window.addEventListener('focus', onFocus) window.addEventListener('blur', onBlur) return () => { window.removeEventListener('focus', onFocus) window.removeEventListener('blur', onBlur) } }, []) return ( <p> App state: <code>{appState}</code>. </p> ); } ``` 4. Fix the code from the previous test to be fully compatible with **ReactNative** keeping existing logic 5. Adjust the following hook which initializes some API. Pre-conditions are: - the initializeAPI function should be called strictly once. - onInitialized callback function may be changed during initialization - after initialization only the latest (value of) onInitialized callback passed should be invoked - we’re assuming the initialization never fails, so no need to add error handling ``` const useMyAPI = onInitialized => { useEffect(() => { initializeAPI().then(onInitialized) }, []) } ``` 6. Optimize the following list render. What are the (at least 2) things missing in the current implementation and how do they affect the rendering process ? ``` const items = Array(10).fill(null).map( (_, index) => ({ id: index + 1, title: `Item #${index + 1}` }) ) const App = () => { const renderItem = (item, index) => ( <li key={index} onClick={() => console.log(item)}> {item.title} </li> ) return ( <ul> {items.map(renderItem)} </ul> ); } ``` ``` const items = Array(10).fill(null).map( (_, index) => ({ id: index + 1, title: `Item #${index + 1}` }) ) const App = () => { const handleOnclick = (item) => console.log(item) const renderItem = (item) => ( <li key={item.id} onClick={handleOnclick}> {item.title} </li> ) return ( <ul> {items.map(renderItem)} </ul> ); } ``` 7. The following hook was designed to debounce value changes. It should change output value each time the source value stops changing (with an ms time gap, e.g. if no changes during this amount of milliseconds - it returns the latest value). What’s wrong with its implementation ? What issues we could have with it and why ? Rewrite this hook and provide the working solution which doesn’t violate the hooks rules. ``` import { useEffect, useState } from 'react'; import { debounce } from 'lodash' const useDebouncedValue = (value, ms = 100) => { const [debounced, setDebounced] = useState(value) useEffect(debounce(() => { setDebounced(value) }, ms), [ms, setDebounced, value]) return debounced } ``` ``` const useDebouncedValue = (value, ms = 100) => { const [debounced, setDebounced] = useState(value); const [debouncedCall, setDeboubcedCall] = useState(() => debounce(setDebounced, ms) ); useEffect(() => { setDeboubcedCall(() => debounce(setDebounced, ms)); }, [ms]); useEffect(() => { debouncedCall(value); }, [value, debouncedCall]); return debounced; }; ``` ``` const useDebouncedValue = (value, ms = 500) => { const [debounced, setDebounced] = useState(value); const debCall = useCallback(debounce(setDebounced, ms), [ms]); useEffect(() => { debCall(value); }, [value, debCall]); return debounced; }; ```