Hook is a new feature in React 16.8. It lets you use state and other React features without having to write a class.

Motivation to use hooks

  1. Hooks allow you to reuse state logic without modifying the component structure. Before hooks, we could use render props and higher-order components to add reusable state logic.

    The render props are a technique for sharing code between React components using a prop function with a function value. The component receives a function that returns the React element and calls this function inside the component to complete the rendering logic. (The prop is called Render or whatever), and it doesn’t have to be in the attribute list of a JSX element, it can be inside the element tag.

    A Higher Order Component is a function that takes a Component and returns a new Component. HOC wraps components in container components to make up new components to accomplish some reusable logic.

    But both scenarios require reorganizing the structure of the components, which can make the code difficult to understand. Hooks allow you to extract state logic from components so that they can be individually tested and reused without modifying the component structure.

  2. When we maintain components, the lifecycle functions of the component tend to become bloated over time, with a lot of unrelated state logic. Hooks break down the interrelated parts of a component into smaller functions (such as setting up subscriptions or requesting data) rather than enforcing partitioning by lifecycle.

  3. Hook allows you to use more React features in non-class situations. No need to understand class

The characteristics of the Hook

When we use functional components, try to write pure functions. If we need functions with React state and life cycle features, we use hooks to fulfill the requirements that can only be implemented in the class. Hook is

  • Totally optional
  • 100% backward compatibility
  • Now available
  • There are no plans to remove classes from React

Hook usage rules

  • Call a Hook only from the outermost layer of a function, not from loops, conditional judgments, or child functions.

React does not know which state corresponds to which useState. It depends on the order in which hooks are executed. If we use hooks in conditional statements, we may change the order in which hooks are executed, resulting in bugs. If we want to perform an effect conditionally, we can put the judgment inside the Hook.

  • This can only be called from the React functional component, not from other JavaScript functions.

React hooks

useState

Equivalent to state in a class component.

When we call useState, we pass in an argument as the initial value of the state, which returns an array of two elements representing the current state value and a function that updates the state, such as [count, setCount] = useState(0), With array deconstruction, we get two variables, count is the variable name of the state, and we can call setCount to update the state of count.

When using useState, should you use a single state variable or wrap all states with a single object?

React officially recommends splitting state into multiple state variables, because updating a state replaces the entire value with the new value, unlike merging setState in the class component. So if an object must contain all the states, the state update should be implemented like this:

const [state, setState] = useState({ left: 0, top: 0, width: 100, height: 100 }); . / Expand "...state "to make sure we don't" lose "width and height setState(state => ({... state, left: e.pageX, top: e.pageY }));Copy the code

useEffect

useEffect(() = > {...}, []);
Copy the code

Fetching data, setting up subscriptions, and manually changing the DOM in the React component are all side effects. We can use useEffect to do this in functional components.

Clear action: Simply return a function in the return value, and React will perform a clear action and call it when the component is uninstalled, such as unsubscribe.

By default, useEffect is executed after every render. To tell React to skip the effect call, we can pass an array as the second argument. For example, if we pass [count] as the second argument, then only if count changes, The side effect function is executed.

// componentDidMount and componentWillUnmount
useEffect(() = >{... }, [])// Will keep an eye on the count and execute whenever the count value changes
useEffect(() = >{... }, [count])// componentDidMount and componentDidUpdate by default
useEffect(() = >{... })Copy the code

useContext

A hook to share state between components. In React, if we want to pass variables, we can pass them down to child components using the props property. This is simple, but when we want to pass a variable to a child of a child component, we need to pass it down using the props of the child component, thus creating a deep injection of props. The deeper the props injection, the more frequently the components are updated, the slower the UI becomes.

UseContext is designed to solve the problem of data sharing between non-parent and child components.

Let’s say we need to share a variable globally, username.

As a first step, we use the React Context API to create a Context outside the component and pass in default initial values.

const defaultContextValue = { username: 'sxx' };
const appContext = React.createContext(defaultContextValue)
Copy the code

Then, in order for the App component and its children to share the username, we wrap the entire Render function with AppContext. Provider. And inject defaultContextValue into the value property.

<appContext.Provider value={defaultContextValue}>
  <App />
</appContext.Provider>
Copy the code

Next, we can access the username variable in its descendant component.

There are two ways:

  1. Using the appContext.consumer component, use curly braces inside the component and use the arrow function to share data within it:
import { appContext } from. . <appContext.Consumer> {(value) = >{{/* You can access the global username */}
    <h1>{value.username}</h1>
  }}
</appContext.Consumer>
Copy the code
  1. React Hook. Using the useContext hook function, we can easily retrieve data from the component without changing the structure of the code:
import { useContext } from 'react';
const value = useContext(appContext);
// Then we can use value directly in return
Copy the code

The useContext hook greatly reduces the template code, reduces the code hierarchy, and eliminates the possibility of multiple consumer nesting.

useReducer

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

This hook takes a reducer and initialState function that returns the current state and dispatch action and can manage data state without using Redux.

const myReducer = (state, action) = > {
  switch(action.type)  {
    case('countUp') :return  {
        ...state,
        count: state.count + 1
      }
    default:
      returnstate; }}// Component code
function App() {
  const [state, dispatch] = useReducer(myReducer, { count:   0 });
  return  (
    <div className="App">
      <button onClick={()= > dispatch({ type: 'countUp' })}>
        +1
      </button>
      <p>Count: {state.count}</p>
    </div>
  );
}
Copy the code

Customize the Hook

Custom hooks are named starting with use and do not need to have a special identity. We are free to decide what its arguments are and what it should return (if necessary).

References:

  1. React Hook Official documentation
  2. React Hooks introduction