Yan's Code Blog

🍓 Welcome to my tech blog. ☕

Learning Notes about React Hooks with TypeScript

2023-03-16

Notes would cover

  • useState: Declare a new state variable, which we'll call "count"

    const [count, setCount] = useState(0);
  • useEffect:

    // Similar to componentDidMount and componentDidUpdate:
    useEffect(() => {
      // Update the document title using the browser API
      document.title = `You clicked ${count} times`;
    });
  • useCallback: Returns a memoized callback.
    Pass an inline callback and an array of dependencies. useCallback will return a memoized version of the callback that only changes if one of the dependencies has changed. This is useful when passing callbacks to optimized child components that rely on reference equality to prevent unnecessary renders (e.g. shouldComponentUpdate).

    const memoizedCallback = useCallback(() => {
      doSomething(a, b);
    }, [a, b]);
  • useMemo: Returns a memoized value.
    Pass a “create” function and an array of dependencies. useMemo will only recompute the memoized value when one of the dependencies has changed. This optimization helps to avoid expensive calculations on every render.
    Remember that the function passed to useMemo runs during rendering. Don’t do anything there that you wouldn’t normally do while rendering. For example, side effects belong in useEffect, not useMemo.
    If no array is provided, a new value will be computed on every render.

    const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
  • useRef: Returns a mutable ref object whose .current property is initialized to the passed argument (initialValue). The returned object will persist for the full lifetime of the component.
    Note that useRef() does not notify you when its content changes. Mutating the .current property does not cause a re-render. If you want to run some code when React attaches or detaches a ref to a DOM node, you may want to use a callback ref instead.

    const refContainer = useRef(initialValue);

    A common use case is to access a child imperatively:

    function TextInputWithFocusButton() {
      const inputEl = useRef(null);
      const onButtonClick = () => {
        // `current` points to the mounted text input element
        inputEl.current.focus();
      };
      return (
        <>
          <input ref={inputEl} type="text" />
          <button onClick={onButtonClick}>Focus the input</button>
        </>
      );
    }

🧪 Code examples

import {
  useState,
  useEffect,
  useCallback,
  useMemo,
  useRef,
  MouseEvent,
  KeyboardEvent,
} from "react";
interface User {
  id: number;
  username: string;
}
type fibonacciFunc = (n: number) => number;
const fibonacci: fibonacciFunc = (n) => {
  if (n < 2) return n;
  return fibonacci(n - 1) + fibonacci(n - 2); //recursive function
};
const myNumber: number = 10; //type annotation, not type inference

const App = () => {
  const [count, setCount] = useState<number>(0);
  const [users, setUsers] = useState<User[] | null>(null);
  const inputRef = useRef<HTMLInputElement>(null);
  //useRef is a hook that returns a mutable ref object whose .current property is initialized to the passed argument (initialValue). The returned object will persist for the full lifetime of the component.
  //we definitly want to say it's an HTML input element becasue that what we are going to reference, but we could use a non-null assertion operator to say that we know it's not null 'null!'
  // but I use other way
  console.log(inputRef?.current);
  console.log(inputRef?.current?.value);

  useEffect(() => {
    console.log("mounting");
    console.log("Users: ", users);
    return () => console.log("unmounting");
  }, [users]);
  //it would call this use effect into action when the users state changes, run once when the component mounts and run once when the component unmounts
  const addTwo = useCallback(
    (
      e: MouseEvent<HTMLButtonElement> | KeyboardEvent<HTMLButtonElement>
    ): void => setCount((prev) => prev + 2),
    []
  );

  const result = useMemo<number>(() => fibonacci(myNumber), [myNumber]);
  //void means it doesn't return anything
  return (
    <div className="App">
      <h1>{count}</h1>
      <button onClick={addTwo}>Increment</button>
      <h2>{result}</h2>
      <input ref={inputRef} type="text" />
    </div>
  );
};

export default App;

📚 References

Learn from here

⬆️ Back to top