文章目录
- useState
- useEffect
- useReducer
- useCallback
- useMemo
- useRef
- useLayoutEffect
- useContext
- useLatest
useState
1
2
3
4
5
6
7
8
9
10
11
12// 返回一个 state,以及更新 state 的函数。 initialState 为初始值 // initialState 参数只会在组件的初始渲染中起作用,后续渲染时会被忽略 const [state, setState] = useState(initialState); // 更新state值的两种方法 setState(initialState) setState(prevCount => prevCount + 1)) // 与 class 组件中的 setState 方法不同,useState 不会自动合并更新对象。你可以用函数式的 setState 结合展开运算符来达到合并更新对象的效果 setState(prevState => { // 也可以使用 Object.assign return {...prevState, ...updatedValues}; });
useEffect
在函数组件主体内(这里指在 Taro 渲染或创建数据的阶段)改变 DOM、添加订阅、设置定时器、记录日志以及执行其他包含副作用的操作都是不被允许的,因为这可能会产生莫名其妙的 bug 并破坏 UI 的一致性。
默认情况下,effect 将在每轮渲染结束后执行,但你可以选择让它在只有某些值改变的时候才执行
清除 effect
1
2
3
4
5
6
7
8
9// 通常,组件卸载时需要清除 effect 创建的诸如订阅或计时器 ID 等资源 useEffect(() => { const subscription = props.source.subscribe(); return () => { // 清除订阅 subscription.unsubscribe(); }; });
第二个参数
1
2
3
4
5
6
7
8
9
10
11// 此时,只有当 props.source 改变后才会重新创建订阅 useEffect( () => { const subscription = props.source.subscribe(); return () => { subscription.unsubscribe(); }; }, [props.source], );
useReducer
1
2const [state, dispatch] = useReducer(reducer, initialArg, init);
useState
的替代方案。它接收一个形如 (state, action) => newState
的 reducer,并返回当前的 state 以及与其配套的 dispatch
方法。(如果你熟悉 Redux 的话,就已经知道它如何工作了。)
以下是用 reducer 重写 useState
一节的计数器示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22const initialState = {count: 0}; function reducer(state, action) { switch (action.type) { case 'increment': return {count: state.count + 1}; case 'decrement': return {count: state.count - 1}; default: throw new Error(); } } function Counter({initialState}) { const [state, dispatch] = useReducer(reducer, initialState); return ( <View> Count: {state.count} <Button onClick={() => dispatch({type: 'increment'})}>+</Button> <Button onClick={() => dispatch({type: 'decrement'})}>-</Button> </View> ); }
useCallback
1
2
3
4
5
6
7
8// 返回一个memoized回调函数。 const memoizedCallback = useCallback( () => { doSomething(a, b); }, [a, b], );
把内联回调函数及依赖项数组作为参数传入 useCallback
,它将返回该回调函数的 memoized 版本,该回调函数仅在某个依赖项改变时才会更新。当你把回调函数传递给经过优化的并使用引用相等性去避免非必要渲染(例如 shouldComponentUpdate
)的子组件时,它将非常有用。
useCallback(fn, deps)
相当于 useMemo(() => fn, deps)
。
useMemo
memoized
函数实现原理:使用一组参数初次调用函数时,缓存参数和计算结果,当再次使用相同的参数调用该函数时,直接返回相应的缓存结果
1
2
3// 返回一个 memoized 值。 const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
把“创建”函数和依赖项数组作为参数传入 useMemo
,它仅会在某个依赖项改变时才重新计算 memoized 值。这种优化有助于避免在每次渲染时都进行高开销的计算。
记住,传入 useMemo
的函数会在渲染期间执行。请不要在这个函数内部执行与渲染无关的操作,诸如副作用这类的操作属于 useEffect
的适用范畴,而不是 useMemo
。
如果没有提供依赖项数组,useMemo
在每次渲染时都会计算新的值
useRef
1
2const refContainer = useRef(initialValue);
useRef
返回一个可变的 ref 对象,其 .current
属性被初始化为传入的参数(initialValue
)。返回的 ref 对象在组件的整个生命周期内保持不变。
一个常见的用例便是命令式地访问子组件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14function TextInputWithFocusButton() { const inputEl = useRef(null); const onButtonClick = () => { // `current` 指向已挂载到 DOM 上的文本输入元素 inputEl.current.focus(); }; return ( <View> <Input ref={inputEl} type="text" /> <Button onClick={onButtonClick}>Focus the input</Button> </View> ); }
useLayoutEffect
其函数签名与 useEffect
相同,但它会在所有的 DOM 变更之后同步调用 effect。可以使用它来读取 DOM 布局并同步触发重渲染。在浏览器执行绘制之前,useLayoutEffect
内部的更新计划将被同步刷新。
尽可能使用标准的 useEffect
以避免阻塞视觉更新。
提示
如果你正在将代码从 class 组件迁移到使用 Hook 的函数组件,则需要注意
useLayoutEffect
与componentDidMount
、componentDidUpdate
的调用阶段是一样的。但是,我们推荐你一开始先用useEffect
,只有当它出问题的时再尝试使用useLayoutEffect
。
useContext
1
2const value = useContext(MyContext)
接收一个 context (Taro.createContext
的返回值)并返回该 context 的当前值。当前的 context 值由上层组件中最先渲染的 <MyContext.Provider value={value}>
的 value
决定。
当组件上层最近的 <MyContext.Provider>
更新时,该 Hook 会触发重渲染,并使用最新传递给 MyContext provider 的 context value
值。
别忘记 useContext
的参数必须是 context 对象本身:
正确: useContext(MyContext)
错误: useContext(MyContext.Consumer)
错误: useContext(MyContext.Provider)
调用了 useContext
的组件总会在 context 值变化时重新渲染。
如果你在接触 Hook 前已经对 context API 比较熟悉,那应该可以理解,
useContext(MyContext)
相当于 class 组件中的static contextType = MyContext
或者<MyContext.Consumer>
。useContext(MyContext)
只是让你能够读取 context 的值以及订阅 context 的变化。你仍然需要在上层组件树中使用<MyContext.Provider>
来为下层组件提供 context
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34const themes = { light: { foreground: "#000000", background: "#eeeeee" }, dark: { foreground: "#ffffff", background: "#222222" } }; const ThemeContext = React.createContext(themes.light); function App() { return ( <ThemeContext.Provider value={themes.dark}> <Toolbar /> </ThemeContext.Provider> ); } function Toolbar(props) { return ( <div> <ThemedButton /> </div> ); } function ThemedButton() { const theme = useContext(ThemeContext); return ( <button style={{ background: theme.background, color: theme.foreground }}> I am styled by theme context! </button> ); }
useLatest
可以随时确保获取的是最新值,并且也可以解决闭包问题
1
2
3
4
5
6
7
8
9import { useRef } from 'react'; const useLatest = <T>(value: T) => { const ref = useRef(value) ref.current = value return ref }; export default useLatest;
最后
以上就是落后猫咪最近收集整理的关于React Hooks 常用API的全部内容,更多相关React内容请搜索靠谱客的其他文章。
发表评论 取消回复