Espen Henriksen

Front-end team lead

Oslo Market Solutions

 

espen_dev

esphen

React Hooks

An introduction

What the hook?

Hooks

  • New API
  • Introduced in React 16.8
  • "Hook into" React features
  • Use state and other features without writing a class
  • Not breaking, classes still around
  • The future of components

Why now?

  • Classes only way to use state
  • Classes are verbose, explicit and imperative
  • Other patterns have emerged
  • HoCs are hard
  • Render prop components incur "wrapper hell"
  • Consolidate these stateful patterns into a first-class citizen

What's wrong with classes?

Challenges today

  • Boilerplate
  • Reusing stateful logic between components
  • Related logic is fragmented
  • Classes are hard for people
  • Classes are hard for machines

Rethinking React

  • Use react features by calling a function
  • Side effects consistent by default
  • Colocate stateful logic into functions
  • Extract functions of related stateful logic
  • Re-use extracted stateful functions

Hooks!

  • Solve most of the issues with classes
  • 100% backwards-compatible
  • Almost all usecases for classes are covered
  • No new concepts like generators or HoCs
  • No plans to remove classes from React

Let's use hooks!

Live coding

In summary

Ergronomic API

Custom hooks

Data fetching is coming

Constraints

  • Rely on call order
  • Only call hooks at the top level
  • No conditional hooks
  • No hooks in loops
  • Only in functional components

No conditional hooks

  // 🔴 We're breaking the first rule by using a Hook in a condition
  if (name !== '') {
    useEffect(function persistForm() {
      localStorage.setItem('formData', name);
    });
  }


  useEffect(function persistForm() {
    // 👍 We're not breaking the first rule anymore
    if (name !== '') {
      localStorage.setItem('formData', name);
    }
  });

ESLint plugin

Types of hooks

useState

const [state, setState] = useState(initialState);

useEffect

useEffect(didUpdate, shouldUpdateFor);

// Example
useEffect(() => {
  setInterval(doSomething, interval);
  return () => {
    clearInterval(doSomething);
  };
}, [interval])

useContext

const contextValue = useContext(Context);

useReducer

const [state, dispatch] = useReducer(reducer, initialArg, init);

// Example
const initialState = {count: 0};

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return {count: state.count + 1};
    case 'decrement':
      return {count: state.count - 1};
    default:
      throw new Error();
  }
}

function Counter({initialCount}) {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({type: 'increment'})}>+</button>
      <button onClick={() => dispatch({type: 'decrement'})}>-</button>
    </>
  );
}

Memoization

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

// Returns a memoized value
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

useRef

const refContainer = useRef(initialValue);

useDebugValue

useDebugValue(value);

// Example

// Show a label in DevTools next to this Hook
// e.g. "FriendStatus: Online"
useDebugValue(isOnline ? 'Online' : 'Offline');

What next?

Watch the talk

Read the docs

Start using it!

Fin

Questions?

https://slides.com/esphen/hooks

Made with Slides.com