Hooks problem to be fixed

Logical reuse between components

The common solutions available are render props and higher-order Components, which also come with a problem: retooling the component structure

The logical call chain is long and hard to understand

Form a nested hell of components

Complex components are difficult to understand

Components become more complex:

Initially simple class components become more complex and difficult to break down as their functionality increases

The lifecycle mechanism separates related code into different parts and brings unrelated code back together, making it easy to introduce bugs

Introduce a variety of libraries to increase project complexity

Class component redundancy

Class components have a number of inconveniences: this

Bind event handlers

Code long

.

The core idea of Hooks

Reduce component nesting, aggregate related logic, and extract fine-grained reusable components

The core API Hooks

useState(initialState)

import React, { useState } from 'react'

function Count() {
  const [count, setCount] = useState(0)
  const [lazyState, setLazyState] = useState(() = > expensiveComputation())

  return (
    <div>
      <p>lazy state {lazyState}</p>
      <p>you clicked {count} times</p>
      <button onClick={()= > setCount(count + 1)}>+</button>
      <button onClick={()= > setCount(prevCount => prevCount - 1)}>-</button>
    </div>)}Copy the code

useEffect(fn, [dependencyList])

import React, { useState, useEffect } from 'react'

function List() {
  const [dataList, setDataList] = useState([])
  const [searchValue, setSearchValue] = useState('123')
  
  useEffect(() = > {
    consoloe.log(searchValue)
  })
  
  useEffect(() = > {
    async function fetchData(value) {
      const result = await fetch('xxx')
      setDataList(result.data);
    }
    fetchData(searchValue)
  }, [searchValue])

  useEffect(() = > {
    function scroll() {
        / *... * /
    }
    window.addEventListener('scroll', scroll)
    return () = > {
      window.removeEventListener('scroll', scroll)
    }
  }, [])

  return (
    <div>
      <input
        value={searchValue}
        onChange={e= > setSearchValue(e.target.value)}
      />
      <ul>
        <li>
          {dataList.map((data, index) => <li key={index}>{data.text}</li>)}
        </li>
      </ul>
    </div>)}Copy the code

useLayoutEffect(fn, [dependencyList])

The synchronous version of useEffect is used to calculate the element position, style and other attributes during dom updates

Additional API Hooks

useReducer(reducer, initialState)

import React, { useState, useReducer } from 'react'

/* base implements */
function useReducer(reducer, initialState) {
  const [state, setState] = useState(initialState)
  function dispatch(action) {
    const newState = reducer(state, action)
    setState(newState)
  }
  return [state, dispatch]
}

function reducer(state = 0, action) {
  switch(action.type) {
    case 'increase': return state - 1
    case 'decrease': return state + 1
    default: return state
  }
}


function Count() {
  const [count, dispatch] = useReducer(reducer, 0)
  return (
    <div>
      <p>you clicked {count} times</p>
      <button onClick={()= > dispatch({action: 'increase'})}>+</button>
      <button onClick={()= > dispatch({action: 'decrease})}>-</button>
    </div>)}Copy the code

useCallback(fn, [dependencyList])

import React, { useState, useCallback, memo } from 'react'

const Button = memo(props= > {
  useEffect(() = > {
    console.log('rendered')})return (
    <button onClick={props.onClick}>{props.children}</button>)})function Counter({initialCount = 0}) {
  const [count, setCount] = useState(initialCount);
  
  const memoClick = useCallback(() = > {
    setCount(prevCount= > prevCount + 1)}, [])return (
    <>
      Count: {count}
      <Button onClick={memoClick}>+</Button>
      <Button onClick={()= > setCount(count - 1)}>-</Button>
    </>
  );
}
Copy the code

useMemo(() => fn, [dependencyList])

import React, { useState, useCallback, useMemo } from 'react'

function Counter({initialCount = 0}) {
  const [count, setCount] = useState(initialCount);
  
  // useCallback(fn, deps) is equivalent to useMemo(() => fn, deps)
  const memoClick = useMemo(() = > () = > {
    setCount(prevCount= > prevCount + 1)}, [])/ *... * /
}

Copy the code

useRef(initialValue)

import React, { useRef } from 'react'

function TextInputWithFocusButton() {
  const inputEl = useRef(null)
  const onButtonClick = () = > {
    inputEl.current.focus()
  }
  return (
    <>
      <input ref={inputEl} type="text" />
      <button onClcik={onButtonClick}>Focus the input</button>
    </>)}function Button() {
  const count = useRef(null)
  return (
    <button>rendered {count.current++} times</button>)}Copy the code

Hooks recommendation rules

Only Call Hooks at the Top Level

Don’t call Hooks inside loops, conditions, or nested functions. Instead, always use Hooks at the top level of your React function.

Only Call Hooks from React Functions

Call Hooks from React function components. Call Hooks from custom Hooks

read

Hooks API Reference

Hooks FAQ

UseEffect complete guide

How do I use useCallback incorrectly