Why use hook in rect?
-
In React, hooks are a way to add stateful behavior and other features to functional components.
-
Before the React version 16.8, stateful behavior could only be achieved in class components using the
stateobject and lifecycle methods likecomponentDidMount,componentDidUpdate, etc.
useState
-
setState支持stateless组件有自己的state
-
入参:具体值或一个函数
-
返回值:数组
-
第一项是state值
-
第二项负责派发数据更新,组件渲染
-
setState会让组件重新执行 => 配合useMemo或useCallback
- 当更新函数之后,state的值是不能即时改变的,只有当下一次上下文执行的时候,state值才随之改变
useEffect
two arguments
-
A function that represents the side effect you want to perform.
-
An optional array of dependencies (dependencies array).
use
-
Performing Side Effects
-
You can use
useEffectto execute code that has side effects -
like fetching data from an API, updating the DOM, setting up event listeners, etc.
-
Since these side effects should not block the rendering of the component,
useEffectallows them to happen after the component has rendered.
-
-
Running Effects Once (ComponentDidMount)
-
If you pass an empty array (
[]) as the second argument touseEffect, the effect function will only run once, after the initial render. -
This is similar to the
componentDidMountlifecycle method in class components.
-
-
Running Effects When Dependencies Change (ComponentDidUpdate):
-
The effect will run whenever any of the dependencies in the array change.
-
This is useful for scenarios where you want to re-run the effect based on specific state or prop changes
- similar to the
componentDidUpdatelifecycle method in class components.
-
-
Cleaning Up Effects (ComponentWillUnmount):
-
If the effect function returns a cleanup function, React will run this cleanup function when the component is unmounted or before the effect is run again due to a dependency change.
-
This helps you clean up any resources or subscriptions created by the effect, preventing memory leaks.
-
useEffect无法直接使用async await
useEffect(() => {
const fetchData = async () => {
const data = await fetch('https://xxx.com')
const json = await response.json()
setData(json)
}
// call the function
fetchData()
// make sure to catch any error
.catch(console.error)
}, [])
监听多个属性变化
import React, { useEffect } from 'react'
function MyComponent({ prop1, prop2 }) {
useEffect(() => {
// 当 prop1 或 prop2 发生变化时执行的代码
console.log('prop1 或 prop2 发生了变化')
// 在这里可以执行你想要的操作,比如发送网络请求、更新状态等等
if (prop1 && prop2) {
// 当 prop1 和 prop2 都满足条件时执行的代码
console.log('prop1 和 prop2 都发生了变化')
// 在这里可以执行你想要的操作,比如发送网络请求、更新状态等等
}
}, [prop1, prop2])
return (
// 组件的 JSX
111
)
}
export default MyComponent
javascript - React hook 使用useEffect 如何判断多个值都改变了才执行内部方法? - SegmentFault 思否
useLayoutEffect
-
useEffect:flashing
- Component update mount completed -> The browser dom drawing is completed -> Execute the useEffect callback
-
useLayoutEffect:Stuck and stopped
- Component update mount completed -> Execute the useLayoutEffect callback-> The browser dom drawing is completed
useContext
-
用来获取父级组件传递过来的context值
- 这个当前值就是最近的父级组件 Provider 的value
-
从parent comp获取ctx方式
-
useContext(Context)
-
Context.Consumer
-
/* 用useContext方式 */
const DemoContext = () => {
const value = useContext(Context)
/* my name is aaa */
return <div> my name is {value.name}</div>
}
/* 用Context.Consumer 方式 */
const DemoContext1 = ()=>{
return <Context.Consumer>
{/* my name is aaa */}
{ (value)=> <div> my name is { value.name }</div> }
</Context.Consumer>
}
export default () => {
return (
<div>
<Context.Provider value={{ name: 'aaa' }}>
<DemoContext />
<DemoContext1 />
</Context.Provider>
</div>
)
}
useReducer
-
入参
-
第一个为函数,可以视为reducer
- 包括state 和 action
-
返回值 state (base on action)
-
第二个为state的初始值
-
-
出参
-
第一个是更新后的state值
-
第二个是派发更新的dispatch函数
-
执行dispatch会导致组件re-render
- (另一个是useState)
-
-
-
useReducer+useContext 代替Redux
const DemoUseReducer = () => {
/* number为更新后的state值, dispatchNumber 为当前的派发函数 */
const [number, dispatchNumber] = useReducer((state, action) => {
const { payload, name } = action
/* return的值为新的state */
switch (name) {
case 'a':
return state + 1
case 'b':
return state - 1
case 'c':
return payload
}
return state
}, 0)
return (
<div>
当前值:{number}
{/* 派发更新 */}
<button onClick={() => dispatchNumber({ name: 'a' })}>增加</button>
<button onClick={() => dispatchNumber({ name: 'b' })}>减少</button>
<button onClick={() => dispatchNumber({ name: 'c', payload: 666 })}>赋值</button>
{/* 把dispatch 和 state 传递给子组件 */}
<MyChildren dispatch={dispatchNumber} State={{ number }} />
</div>
)
}
useMemo & useCallback
useMemois used for caching computation results, whileuseCallbackis used for caching function instances. Both hooks aim to optimize React components by controlling when and how often certain calculations and functions are recalculated or recreated."
Custom Hooks - implement a function
update hook
import { useState } from 'react'
const useUpdate = () => {
const [, setFlag] = useState()
const update = () => {
setFlag(Date.now())
}
return update
}
export default useUpdate
// 实际使用
const App = (props) => {
// ...
const update = useUpdate()
return (
<div>
{Date.now()}
<div>
<button onClick={update}>update</button>
</div>
</div>
)
}
useScroll hooks
import { useState, useEffect } from 'react'
const useScroll = (scrollRef) => {
const [pos, setPos] = useState([0, 0])
useEffect(() => {
function handleScroll(e) {
setPos([scrollRef.current.scrollLeft, scrollRef.current.scrollTop])
}
scrollRef.current.addEventListener('scroll', handleScroll)
return () => {
scrollRef.current.removeEventListener('scroll', handleScroll)
}
}, [])
return pos
}
export default useScroll
// 用法
import React, { useRef } from 'react'
import { useScroll } from 'hooks'
const Home = (props) => {
const scrollRef = useRef(null)
const [x, y] = useScroll(scrollRef)
return (
<div>
<div ref={scrollRef}>
<div className="innerBox"></div>
</div>
<div>
{x}, {y}
</div>
</div>
)
}
Hooks VS HOC
-
Hook
-
put more related logic together => replace the lifecycle
-
Suitable for Controller or related logic that needs cohesion
-
-
HOC
-
Put external property functionality into a base Component => Plug-ins for extensibility
- Extend the functionality of components by injecting stateful props instead of writing code directly in the main library
-
Why can't react hooks be placed in if and for?
-
Rules of Hooks: React enforces strict rules for using hooks. Hooks, such as
useState,useEffect, etc., must always be called at the top level of a function component or another custom hook. They should not be placed inside conditionals or loops. -
Order of Execution: Hooks rely on the order in which they are called during each render. Placing them inside conditionals or loops can lead to variations in the order of execution, causing unexpected results and bugs.
-
Avoiding State Inconsistency: Placing hooks inside conditionals or loops can lead to inconsistencies in state updates. React won't be able to guarantee that the same hook will always be executed for the same component, potentially resulting in incorrect behavior.
-
Alternative Approaches: To work with conditional logic or loops in React components, use hooks outside the conditionals or loops. You can control rendering behavior based on the state or props without violating the rules of hooks.
- Hooks can only be used in the top-level scope of function components