You are on page 1of 6

MANAGE STATE • Hook Way

import { useState } from "react";


useState
const initialCount = 0;
function Counter() {
const [count, setCount] = useState(initialCount); const [count, setCount] = useState(initialCount);
return (
<div>
• Class way <p>You clicked {count} times</p>
<button
const initialCount = 0; onClick = {() => setCount((c) => c + 1)}
class Counter extends Component { >
constructor(props) { Click me
super(props); </button>
this.state = { count : initialCount }; </div>
} );
render() { }
return (
<div>
<p>You clicked {this.state.count} times</p>
<button useReducer
onClick = {() => this.setState(({count}) => ({ count: count + 1 }))}
>
const [state, dispatch] = useReducer(
Click me
reducer,
</button>
initialState,
</div>
initialDispatch
);
);
}
}
An alternative to useState. Use it in the components that need
complex state management, such as multiple state values being
updated by multiple methods.

3|Page 4|Page
• Class way
const initialState = {count: 0};
function reducer(state, action) {
switch (action.type) { class FriendStatus extends React.Component {
case 'increment': state = { isOnline : null };
componentDidMount() {
return {count: state.count + 1};
ChatAPI.subscribeToFriendStatus(
case 'decrement':
this.props.friend.id,
return {count: state.count - 1};
this.handleStatusChange
default: );
throw new Error(); }
} componentWillUnmount() {
} ChatAPI.unsubscribeFromFriendStatus(
function Counter({initialState}) { this.props.friend.id,
const [state, dispatch] = useReducer(reducer, initialState); this.handleStatusChange
return ( );
<> }
Count: {state.count} componentDidUpdate(prevProps) {
<button onClick = {() => dispatch({type: 'increment'})}>+</button> if(this.props.friend.id !== prevProps.id) {
ChatAPI.unsubscribeFromFriendStatus(
<button onClick = {() => dispatch({type: 'decrement'})}>+</button>
prevProps.friend.id,
</>
this.handleStatusChange
);
);
} ChatAPI.subscribeToFriendStatus(
this.props.friend.id,
this.handleStatusChange
);
HANDLE SIDE EFFECTS }
}

handleStatusChange = status => {


useEffect this.setState({
isOnline: status.isOnline
});
useEffect(() => { }
applyEffect(dependencies); render() {
return () => cleanupEffect(); if (this.state.isOnline === null) {
}, [dependencies]); return 'Loading...';
}
return this.state.isOnline ? 'Online' : 'Offline';
}
}

5|Page 6|Page
• Hook Way useLayoutEffect is almost same as useEffect, but fires
synchronously after the render phase. Use this to safely read from
import { useState, useEffect } from 'react';
function FriendStatus(props) { or write to the DOM
const [isOnline, setIsOnline] = useState(null);
status
import { useRef, useLayoutEffect } from "react";
const handleStatusChange = (status) => setIsOnline(status.isOnline);
useEffect( function ColoredComponent({color}) {
const ref = useRef();
() => {
// Update status when the listener triggers useLayoutEffect(() => {
ChatAPI.subscribeToFriendStatus( const refColor = ref.current.style.color;
props.friend.id, console.log(`${refColor} will always be the same as ${color}`);
handleStatusChange ref.current.style.color = "rgba(255,0,0)";
}, [color]);
);
// Stop listening to status changes every time we cleanup useEffect(() => {
return function cleanup() { const refColor = ref.current.style.color;
console.log(
ChatAPI.unsubscribeFromFriendStatus(
`but ${refColor} can be different from ${color} if you play with the
props.friend.id,
handleStatusChange DOM`
); );
}; }, [color]);
}, return (
[props.friend.id] // Cleanup when friend id changes or when we "unmount" <div ref={ref} style={{ color: color }}>
); Hello React hooks !
if (isOnline === null) { </div>
return 'Loading...'; );
}
}
return isOnline ? 'Online' : 'Offline';
}
<ColoredComponent color = {"rgb(42, 13, 37)"}/>
// rgb(42, 13, 37) will always be the same as rgb(42, 13, 37)
// but rgb(255, 0, 0) can be different from rgb(42, 13, 37) if you play with the DOM
useLayoutEffect

useLayoutEffect(() => {
applyBlockingEffect(dependencies);
return cleanupEffect();
}, [dependencies]);

7|Page 8|Page
USE THE CONTEXT API • Hook Way

import { useContext } from 'react';


useContext function Header() {
const { handleLogin, isLoggedIn} = useContext(AuthContext);
const { isOpen, showModal, hideModal } = useContext(ModalContext);
const ThemeContext = React.createContext(); const { notification, notify } = useContext(NotificationContext);
const contextValue = useContext(ThemeContext);
return ...
}
• Class way
NOTE: Use the created context, not the consumer.
class Header extends React.Component {
const Context = React.createContext(defaultValue);
public render() {
// Wrong
return (
const value = useContext(Context.Consumer);
<AuthContext.Consumer>
// Right
{({ handleLogin, isLoggedIn}) => (
const value = useContext(Context);
<ModalContext.Consumer>
{({ isOpen, showModal, hideModal }) => (
<NotificationContext.Consumer>
{({ notification, notify }) => {
return (
MEMOIZE EVERYTHING
...
) useMemo
}}
</NotificationContext.Consumer>
)} const memoizedValue = useMemo (
</ModalContext.Consumer> () => expensiveFn (dependencies),
)} [dependencies]
</AuthContext.Consumer> );
);
}
}

9|Page 10 | P a g e
function RandomColoredLetter(props) { USE REFS
const [color, setColor] = useState('#fff')
const [letter, setLetter] = useState('a')
useRef
const handleColorChange = useMemo(() => () =>
setColor(randomColor()), []);
const handleLetterChange = useMemo(() => () => const ref = useRef();
setLetter(randomColor()), []);
return (
<div> useRef can just be used as a common React ref :
<ColorPicker handleChange={handleColorChange} color={color} />
<LetterPicker handleChange={handleLetterChange} letter={letter} /> import { useRef } from "react";
<hr/> function TextInput() {
<h1 style={{color}}>{letter}</h1> const inputRef = useRef(null);
</div> const onBtnClick = () => inputRef.current.focus();
) return (
} <>
<input ref={ref} />
<button onClick={onBtnClick}>Focus the text input</button>
useCallback </>
)
}
const memoizedCallback = useCallback (
expensiveFn (dependencies),
[dependencies] But it also allows you to just hold a mutable value through any
);
render. Also, mutating the value of ref.current will not cause any

function RandomColoredLetter(props) { render.


const [color, setColor] = useState('#fff')
const [letter, setLetter] = useState('a')
const handleColorChange = useCallback(() => setColor(randomColor()), []); useImperativeHandle
const handleLetterChange = useCallback(() => setLetter(randomColor()), []);
return (
useImperativeHandle (
<div>
ref,
<ColorPicker handleChange={handleColorChange} color={color} />
<LetterPicker handleChange={handleLetterChange} letter={letter} /> createHandle,
<hr/> [dependencies]
<h1 style={{color}}>{letter}</h1> )
</div>
)
}

11 | P a g e 12 | P a g e
useImperativeHandle allows you to customize the exposed interface
REUSABILITY
of a component when using a ref. The following component will
automatically focus the child input when mounted : Extract reusable behaviour into custom hooks.

import { useState, useRef, useCallback, useEffect } from "React";


function TextInput(props, ref) { // let's hide the complexity of listening to hover changes
const inputRef = useRef(null); function useHover() {
const onBtnClick = () => inputRef.current.focus(); const [value, setValue] = useState(false); // store the hovered state
useImperativeHandle(ref, () => ({ const ref = useRef(null); // expose a ref to listen to
focusInput: () => inputRef.current.focus(); // memoize function calls
}); const handleMouseOver = useCallback(() => setValue(true), []);
return ( const handleMouseOut = useCallback(() => setValue(false), []);
<Fragment> // add listeners inside an effect,
<input ref={inputRef} /> // and listen for ref changes to apply the effect again
<button onClick={onBtnClick}>Focus the text input</button> useEffect(() => {
</Fragment> const node = ref.current;
) if (node) {
} node.addEventListener("mouseover", handleMouseOver);
const TextInputWithRef = React.forwardRef(TextInput); node.addEventListener("mouseout", handleMouseOut);
function Parent() { return () => {
const ref = useRef(null); node.removeEventListener("mouseover", handleMouseOver);
useEffect(() => { node.removeEventListener("mouseout", handleMouseOut);
ref.focusInput(); };
}, []); }
return ( }, [ref.current]);
<div> // return the pair of the exposed ref and it's hovered state
<TextInputWithRef ref={ref} /> return [ref, value];
</div> }
);
}

const HoverableComponent = () => {


const [ref, isHovered] = useHover();
return (
<span style={{ color: isHovered ? "blue" : "red" }} ref={ref}>
Hello React hooks !
</span>
);
};

13 | P a g e 14 | P a g e

You might also like