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> </> ) }