Welcome to Aaron Blog! en and jp version is now updating! 🎉

Day 6 Advanced and Rendering

Learning the React Framework

Loading comments...

Learning the React Framework - 006 Advanced Hooks and Render Control

With just useState and useEffect, you can actually build simple applications. However, development requirements are often more complex and conditional - we can't just render components immediately whenever dependencies change. We need temporal, operational, and holistic planning. React has also introduced more advanced control functions to allow developers to create richer and more refined operations.

Advanced Hooks

useReducer

Compared to useState, it's easier to operate complex object structures and can update state based on conditions.

const [state, dispatch] = useReducer(reducer, initialArg, init?)
  • reducer: The reducer function that specifies how state should be updated. It must be pure, should take state and action as parameters, and should return the next state. State and action can be of any type.
  • initialArg: The value used to calculate the initial state. It can be a value of any type. How the initial state is calculated from it depends on the next init parameter.
  • optional init: The initialization function that should return the initial state. If not specified, the initial state is set to initialArg. Otherwise, the initial state will be set to the result of calling init(initialArg). This can avoid recreating the initial state, i.e., lazy initialization.
  • state: The current state
  • dispatch: Function that can update state to a different value and trigger re-rendering.

By separating it into actionType and reducer encapsulation, we can perform more complex object operations, and through IDE hints, we can quickly find corresponding operation methods. Note that the official documentation repeatedly mentions the need to provide pure operations to avoid side effects causing unexpected component changes and rendering.

useCallback

Optimizes function callbacks, but whether it's necessary in usage still requires self-judgment, as it might not optimize and even become slower QQ

const cachedFn = useCallback(fn, dependencies);

The first parameter is the cached function value, and the second parameter is a dependency array, similar to useEffect. When a dependency changes between renders, the callback passed in the first parameter will be the callback returned from useCallback. If they haven't changed, you'll get the previously returned callback (so the callback remains the same between renders). Through useCallback, you can remember the memory location of a function, which can avoid React.memo re-rendering when comparing props values due to different memory locations but same values for object types.

However, since this Hook uses a caching pattern, unless specifically necessary, it will increase memory burden.

useContext

This Hook is very interesting. Through function encapsulation of your own context environment, more simply put, React provides a global state passing method. When application-level complexity and nesting occur, it can effectively pass state.

import { useContext } from 'react';
const value = useContext(SomeContext);

function MyPage() {
  return (
    <ThemeContext.Provider value="dark">
      <Button />
    </ThemeContext.Provider>
  );
}

function Button() {
  const theme = useContext(ThemeContext); // Can get dark
  const className = `button-${theme}`;
  return (
    <button className={className}>
      Hello
    </button>
  );
}
  • SomeContext: Context created using createContext. The context itself doesn't hold information, it just represents the type of information you can provide or read from components
  • value: useContext returns the context value for the calling component. It's determined as the value passed to the nearest SomeContext.Provider above the calling component in the tree.

useLayoutEffect

useLayoutEffect is a version of useEffect that fires before the browser repaints the screen. When development requirements need to get certain data or state at the beginning, this can be used.

  • before any other effects are called.
  • if the side effect that you are performing makes an observable change to the dom, that will require the browser to paint the update that you made.

useMemo

Can cache calculation results between re-renders.

const cachedValue = useMemo(calculateValue, dependencies);

// Example=>
const allItems = React.useMemo(() => getItems(inputValue), [inputValue]);
  • calculateValue: Function to calculate the value to cache. Should be pure, should have no arguments, and should return a value (of any type). React will call this function during initial render. On next renders, if dependencies haven't changed since the last render, React will return the same value again. Otherwise, it will call calculateValue, return its result, and store it so it can be reused later.
  • dependencies: List of all reactive values referenced inside calculateValue code. Reactive values include props, state, and all variables and functions declared directly inside your component body.

References

Loading comments...