React 创建组件的方式:
- 类组件
- 函数式组件
a. 纯函数组件没有状态
b. 纯函数组件没有生命周期
c. 纯函数组件没有this
d. 只能是纯函数
这就注定,我们所推崇的函数组件,只能做 UI 展示的功能,涉及到状态的管理与切换,我们不得不用类组件或者 redux。
Hook 就是 JavaScript 函树,它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。
Hook 使用规则
-
只能在函数最外层调用 Hook。不要在循环、条件判断或者子函数中调用。
确保总是在你的 React 函数的最顶层以及任何 return 之前调用他们。遵守这条规则,你就能确保 Hook 在每一次渲染中都按照同样的顺序被调用。这让 React 能够在多次的 useState 和 useEffect 调用之间保持 hook 状态的正确。 -
只能在 React 的函数组件、自定义的 Hook中调用 Hook。不要在其他 JavaScript 函数中调用。
常见 hooks
-
useState():返回一个 state,以及更新 state 的函数。
const [state, setState] = useState(initialState)
两种传参方式:
a. 直接传入新值setState(state + 1)
b. 函数式更新setState((prevState) => prevState + 1)
-
useEffect():接收一个包含命令式、且可能有副作用代码的函数
useEffect(() => { const subscription = props.source.subscribe(); return () => { // 清除 effect subscription.unsubscribe() } }[, arg])
不传递第二个参数:默认情况,effect 会在每轮组件渲染完成后执行,一旦组件重新 render,effect 都会被重新创建
第二个参数为空数组:effect 仅在组件挂载和卸载时执行
第三个参数为数组,即依赖项:一旦依赖发生变化,effect 就会被重新创建 -
useLayoutEffect()
它会在所有的 DOM 变更之后同步调用 effect。可以使用它来读取 DOM 布局并同步触发重渲染。在浏览器执行绘制之前,useLayoutEffect 内部的更新计划将被同步刷新。 -
userContext():
const value = useContext(MyContext)
接收一个 context 对象(React.createContext
的返回值)并返回该 context 的当前值。当前的 context 值由上层组件中距离当前组件最近的<MyContext.Provider>
的value
prop 决定。
当组件上层最近的<MyContext.Provider>
更新时,该 Hook 会触发重渲染,并使用最新传递给MyContext
provider 的 contextvalue
值。
别忘记useContext
的参数必须是 context 对象本身: -
userReducer()
两种不同初始化 useReducer state 的方式:
a. 指定初始 state:const [state, dispatch] = useReducer(reducer, initialState)
b. 惰性初始化:const [state, dispatch] = useReducer(reducer, initialArg, init)
,这样初始 state 将被设置为 init(initialArg) -
useCallback():返回一个 memoized 回调函数。
把内联回调函数及依赖项数组作为参数传入useCallback
,它将返回该回调函数的 memoized 版本,该回调函数仅在某个依赖项改变时才会更新。const memoizedCallback = useCallback( () => { doSomething(a, b); }, [a, b], )
-
useMemo():
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b])
返回一个 memoized 值。把“创建”函数和依赖项数组作为参数传入useMemo
,它仅会在某个依赖项改变时才重新计算 memoized 值。传入useMemo
的函数会在渲染期间执行,请不要在这个函数内部执行与渲染无关的操作,如果没有提供依赖项数组,useMemo
在每次渲染时都会计算新的值。
useCallback(fn, deps)
相当于useMemo(() => fn, deps)
-
useRef():
const refContainer = useRef(initialValue)
useRef 返回一个可变的 ref 对象,其.current
属性被初始化为传入的参数(initialValue)。返回的 ref 对象在组件的整个生命周期内持续存在。
当 ref 对象内容发生变化时,useRef
并不会通知你。变更.current
属性不会引发组件重新渲染。
use-immer
- 安装:
npm install immer use-immer
- 使用 useImmer:
返回一个 immer,以及更新 immer 的函数 setImemer。import { useImmer } from "use-immer" const [immer, setImemer] = useImmer({ name: "Ming", sex:'female' age: 18 }) setImemer(draft => { draft.age++; })
- 使用 useImmerReducer:
对 useReducer 进行了再次封装。用法和 useReducer 一样import React from "react" import { useImmerReducer } from "use-immer" const initialState = { count: 0 } function reducer(draft, action) { switch (action.type) { case "reset": return initialState case "increment": return void draft.count++ case "decrement": return void draft.count-- } } function Counter() { const [state, dispatch] = useImmerReducer(reducer, initialState) return ( <> Count: {state.count} <button onClick={() => dispatch({ type: "reset" })}>Reset</button> <button onClick={() => dispatch({ type: "increment" })}>+</button> <button onClick={() => dispatch({ type: "decrement" })}>-</button> </> ) }
网友评论