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