React Hooks: Notes Taken

Tomáš Konrády
3 min readOct 26, 2018

--

References

Installation

yarn add react@next react-dom@next

Basic example

const FriendStatus = ({ id }) => {
const [isOnline, setIsOnline] = useState(null);
const handleStatusChange = (status) => {
setIsOnline(status.isOnline);
}
useEffect(() => {
ChatAPI.subscribeToFriendStatus(id, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(id, handleStatusChange);
};
});
if (isOnline === null) {
return 'Loading...';
}
return isOnline ? 'Online' : 'Offline';
}

Basic rules

  • Only call Hooks at the top level.
  • Only call Hooks from React function components.

See aforementioned ESLint plugin.

So…

  • They can’t be used within class components
  • They can’t be used in combination with for, if, ... as they relies on an order in which they are called.

useState

Example

const Balloon = ({ initialSize, powerOfBlow }) => {
const [size, setSize] = useState(initialSize);

const onBlow = () => setSize(size + powerOfBlow)
return <div onClick={onBlow}>Size of the balloon: {size}</div>;
}

Syntax:

@param {any} Initial state value
@returns Pair
- fst {any} Value of state
- snd {function} callback to set new value of state
  • Type of the state can be anything unlike state within class components (in that case object must be used).
  • It is encouraged to use multiple useState within a function component, instead of using one single state object as is in class components.
  • Possible minification

useEffect

Example:

useEffect(() => {
document.title = `You clicked ${count} times`;
return () => {
document.title = 'You have never clicked!';
}
});

Syntax:

@param {Function} effect Function that is called when component performs DOM changes.
@param {Array} shouldApply Array of values that should be checked for changes before applying an effect. If values between renders do not change, the effect is not applied again.
@returns {Function} Cleanup function that is called before a component is unmounted and before new render.

Notes:

  • For side effects :) DOM, logs, fetching APIs…
  • It is called after every render — even the first one.
  • Unlike class lifecycle methods the useEffect do not block the browser.
  • For blocking effects there is useLayoutEffect.

shouldUpdate?

useEffect(() => {
ChatAPI.subscribeToFriendStatus(props.id, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(props.id, handleStatusChange);
};
}, [props.id]);
  • For checking the shouldApply parameter the shallow compare is used.
  • Use [] if you need to use effect just for both didMount and willUnmount phases. It is discouraged.

Custom hooks

const useFriendStatus = (id) => {
const [isOnline, setIsOnline] = useState(null);
const handleStatusChange = (status) => {
setIsOnline(status.isOnline);
}
useEffect(() => {
ChatAPI.subscribeToFriendStatus(id, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(id, handleStatusChange);
};
});
return isOnline;
}
const FriendStatus = ({ id }) => {
const isOnline = useFriendStatus(id);
if (isOnline === null) {
return 'Loading...';
}
return isOnline ? 'Online' : 'Offline';
}
  • The name of a function starts with use, e.g. useRedux.
  • Two components that use the same hooks does not share the same state.
  • Use cases: form handling, animation, declarative subscriptions, timers, …

Other Hooks

useCallback

const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b],
);

useReducer

const reducer = (state, action) => {
switch (action.type) {
case 'reset':
return {count: action.payload};
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
}
}
const [state, dispatch] = useReducer(
reducer,
initialState,
{ type: 'reset', payload: initialCount },
);

useRef && useImperativeMethods

  • Another way to use refs…

React-redux

  • Use React.useReducer for local state
  • Use ReactRedux.useRedux for global state
import * as actions from './actions'const Counter = () => {
const [count, {increment, decrement}] = useRedux(state => state.count, actions);

return (
<Fragment>
Count: {count}
<button onClick={() => increment()}>+</button>
<button onClick={() => decrement()}>-</button>
</Fragment>
);
}

--

--