React Hooks

Hooks are new in React 16.8. It allows you to use class component lifecycle functions and React features such as state while writing function components.

1. useState()

Basic usage

UseState () is a Hook provided by React to read and modify state. The first argument it passes in, initialState, is the initial value of state, which returns a state and the function setState that updates state. During initial rendering, the state state returned is the same value as the first parameter, initialState, passed in.

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

The setState function is used to update state. It receives a new state value and enqueues a rerendering of the component.

setState(newState);
Copy the code

Functional update

If the new state needs to be computed using the previous state, you can pass the function to setState. This function will take the previous state and return an updated value. The following counter component example shows two uses of setState:

function Counter({initialCount}) {
  const [count, setCount] = useState(initialCount);
  return (
    <>
      Count: {count}
      <button onClick={()= > setCount(initialCount)}>Reset</button>
      <button onClick={()= > setCount(prevCount => prevCount - 1)}>-</button>
      <button onClick={()= > setCount(prevCount => prevCount + 1)}>+</button>
    </>
  );
}
Copy the code

The “+” and “-” buttons are functional because the updated state needs to be based on the previous state. But the reset button takes the normal form, because it always sets the count back to its initial value.

Attention!

Unlike update data in the Vue framework, useState does not automatically merge update objects. You can combine the function setState with the expansion operator to achieve the effect of merging updated objects.

setState(prevState= > {
  return{... prevState, ... updatedValues}; });Copy the code

2. useEffect()

The basic concept

UseEffect () adds the ability to use a lifecycle to function components. It has the same purpose as componentDidMount, componentDidUpdate, and componentWillUnmount, but is combined into a single API.

1. The simulationcomponentDidMountLife cycle function

useEffect(() = > {
    // Mount the component and execute it
  },[]);
Copy the code

2. The simulationcomponentDidUpdateLife cycle function

const [count,setCount] = useState(1);

// Any state change will trigger
useEffect(() = > {
    // Execute after any state change
  });

// Specify dependent state changes to trigger
useEffect(() = > {
    // Execute after the count change
},[count]);
Copy the code

3. The simulationcomponentWillUnmountLife cycle function

const [count,setCount] = useState(1);
useEffect(() = > {
    // Mount the component and execute it
    return function(){
        // Execute before component uninstallation}} []);Copy the code

3. useContext()

Basic usage

const value = useContext(MyContext);
Copy the code

UseContext () is used to solve the problem of child components receiving props from their grandparents and up. The code is organized in a way similar to the publish-and-subscribe pattern: the ancestral component provides the context -> child component with the value property of < myContext.provider > and gets the context through useContext(MyContext). UseContext () receives a context object (the value returned by React.createcontext) and returns the current value of that context. The value of the current context is determined by the value property of < myContext. Provider> nearest to the current component in the upper-layer component. When the latest < myContext. Provider> update is made to the component’s upper layer, the Hook will trigger a rerender, using the last context value passed to MyContext Provider.

Code sample

const themes = {
  light: {
    foreground: "# 000000".background: "#eeeeee"
  },
  dark: {
    foreground: "#ffffff".background: "# 222222"}};/ / create the Context
const ThemeContext = React.createContext(themes.light);

// Specify the scope of the Context and the value of the attribute passed.
function App() {
  return (
    <ThemeContext.Provider value={themes.dark}>
      <Toolbar />
    </ThemeContext.Provider>
  );
}

function Toolbar(props) {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

function ThemedButton() {
  // Get the attribute value provided by themecontext. Provider value
  const theme = useContext(ThemeContext);
  return (
    <button style={{ background: theme.background.color: theme.foreground}} >
      I am styled by theme context!
    </button>
  );
}
Copy the code

4. useReducer()

The basic concept

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

UseReducer () is an alternative to useState(). Compared to useState(), useReducer() passes in an extra operation on state — reducer (reducer is a function like (state, action) => newState), Returns the current state and its corresponding dispatch method.

The sample program

Here is an example of the counters in overriding useState with Reducer:

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() {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <>
      Count: {state.count}
      <button onClick={()= > dispatch({type: 'decrement'})}>-</button>
      <button onClick={()= > dispatch({type: 'increment'})}>+</button>
    </>
  );
}
Copy the code

5. useRef()

Basic usage

const refContainer = useRef(initialValue);
Copy the code

The semantics of ref is “reference,” and we usually use ref to access DOM nodes. UseRef () returns a mutable ref object whose.current property is initialized to the passed parameter (initialValue). The returned REF object remains the same throughout the lifetime of the component.

Code sample

function TextInputWithFocusButton() {
  const inputEl = useRef(null);
  const onButtonClick = () = > {
    // 'current' refers to the text input element that has been mounted to the DOM
    inputEl.current.focus();
  };
  return (
    <>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}
Copy the code

Save the data

What is there in a component that lasts across render cycles, that is, properties that remain unchanged after the component has been rendered multiple times? The first thing that comes to mind is state. Yes, a component’s state can remain the same after multiple renderings. The problem with state, however, is that modifying it causes the component to be rerendered. UseRef can then be used to store data across the render cycle, and modifying it will not cause the component to render.

6. useMemo()

const memoizedValue = useMemo(() = > computeExpensiveValue(a, b), [a, b]);
Copy the code

Pass the “create” function and dependency array to useMemo() as arguments, and it will only recalcalculate memoized if one of the dependencies changes. This optimization helps to avoid high overhead calculations every time you render.

7. useCallback()

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

Pass the inline callback function and the array of dependencies as arguments to useCallback(), which returns the memoized callback of that callback function, which is updated only if one of the dependencies changes. UseCallback (fn, deps) equals useMemo(() => fn, deps).