一、什么是Hooks
Hooks 是 React 16.8 的新增特性。在不编写 class 的情况下使用 state 以及其他的 React 特性。Hooks 是一种在函数式组件中使用有状态函数的方法。
二、类组件
componentDidMount、componentDidUpdate 和 componentWillUnmount 这三个函数的组合。
三、常用的Hook Api
1、useState使用:用于在组件中添加和管理状态
1.1、比如 const [count, setCount] = useState(0);
1.2、不直接支持依赖项
1.3、支持差不多任意类型的数据,数据发生改变会重新渲染
1.4、不可用返回View
import React, { useState } from 'react';
2 import {
3 SafeAreaView,
4 Text,
5 TouchableOpacity
6 } from 'react-native';
7 import Constants from './expand/dao/Constants';
8 import { post } from './expand/dao/HiNet';
9 export default (props: any) => {
10 const [msg, setMsg] = useState('');
11 const doFetch = () => {
12 const formData = new FormData();
13 formData.append("requestPrams", 'RN');
14 post(Constants.test.api)(formData)().then(result => {
15 setMsg(JSON.stringify(result));
16 }).catch(e => {
17 console.log(e);
18 setMsg(JSON.stringify(e));
19 })
20 }
21 return (
22 <SafeAreaView>
23 <TouchableOpacity onPress={doFetch}>
24 <Text>加载</Text>
25 </TouchableOpacity>
26 <Text>{msg}</Text>
27 </SafeAreaView>
28 );
29 };
从上述代码中我们不难看出,在React Native中使用State Hook的主要步骤:
- 导入
useState:import React, { useState } from 'react'; - 通过
useState定义state:const [msg, setMsg] = useState('');- msg是定义的state中一个变量,setMsg是用来修改msg变量的关联函数,它的格式是
set+变量名首字母大写
- msg是定义的state中一个变量,setMsg是用来修改msg变量的关联函数,它的格式是
- 修改状态:通过前面定义的关联函数
setMsg修改即可setMsg(JSON.stringify(result)); State Hook的作用范围:因为Hooks只能应用与函数式组件,所以通过它声明的state的作用范围是函数内。
2、useEffect使用:组件挂载后/更新后/卸载前都会调用,相当于类组件;componentDidMount、componentDidUpdate 和 componentWillUnmount
1.1、多个useEffect,首次进入,是否有没有依赖都会执行回调;当有依赖的回调数据发生改变,就回调对应有依赖的回调
useEffect(() => {
// 模仿 componentDidMount
console.log('PageDemo is mounted=componentDidMount');
// 模仿 componentWillUnmount
return () => {
console.log('PageDemo will unmount=componentWillUnmount');
};
}, []);
useEffect(() => {
// 模仿 componentDidUpdate
if (prevCountRef.current !== count) {
console.log(`PageDemo is updated from=componentDidUpdate ${prevCountRef.current} to${count}`);
}
prevCountRef.current = count;
}, [count]); // 依赖项数组
- 导入
useEffect:import React, { useState,useEffect } from 'react'; - 使用
useEffect来实现不同生命周期函数的hooks:- 直接写在
useEffect(() => {}一层的会在组件装载时调用,对应componentDidMount handleStatusChange对应componentDidUpdatecleanup对应componentWillUnmount在组件卸载时调
- 直接写在
3、useContext使用
const value = useContext(MyContext);
接收一个 context 对象(React.createContext 的返回值)并返回该 context 的当前值。当前的 context 值由上层组件中距离当前组件最近的 <MyContext.Provider> 的 value prop 决定。
当组件上层最近的 <MyContext.Provider> 更新时,该 Hook 会触发重渲染,并使用最新传递给 MyContext provider 的 context value 值。即使祖先使用 React.memo 或 shouldComponentUpdate,也会在组件本身使用 useContext 时重新渲染。
4、useCallback使用
把内联回调函数及依赖项数组作为参数传入 useCallback,它将返回该回调函数的 memoized 版本,该回调函数仅在某个依赖项改变时才会更新
1.1、可以返回View
1.2、有||没有依赖,当做某个控件点击回调函数,不会主动调用里面方法(需要View调用)
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b],
);
把内联回调函数及依赖项数组作为参数传入 useCallback,它将返回该回调函数的 memoized 版本,该回调函数仅在某个依赖项改变时才会更新。当你把回调函数传递给经过优化的并使用引用相等性去避免非必要渲染(例如 shouldComponentUpdate)的子组件时,它将非常有用。
useCallback(fn, deps) 相当于 useMemo(() => fn, deps)。
没有依赖项的 useCallback
当 useCallback 没有依赖项时,回调函数只会在组件首次渲染时创建,并且永远不会重新创建。这意味着即使组件重新渲染,回调函数也不会改变。
5、useMemo使用
接受两个参数:一个计算函数和一个依赖项数组。当依赖项数组中的值发生变化时,useMemo 会重新执行计算函数;如果依赖项没有变化,它会返回上一次计算的结果。
1.1、可以返回View
1.2、有没有依赖,首次都会渲染。如果有依赖仅会在某个依赖项改变时才重新计算 memoized 值(没有依赖就不会)
1.3、没有提供依赖项数组,通过useState设置数据,也没有重新渲染(注意:官方文档,如果没有提供依赖项数组,useMemo 在每次渲染时都会计算新的值)
const memoizedValue = useMemo(() => {
// 执行一些可能计算量很大的操作
return heavyComputation(a, b);
}, [a, b]);
6、useRef使用:返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)。返回的 ref 对象在组件的整个生命周期内持续存在。
1.1、访问 DOM 元素,拿到对象后调用方法
1.2、保存任意可变值,值的改变不会重新渲染
1.3、不支持依赖项
import React, { useRef } from 'react';
function MyComponent() {
// 创建一个 ref 对象,初始值为 null
const inputRef = useRef(null);
// 绑定 ref 到 input 元素
// <input ref={inputRef} />
// 当按钮被点击时,聚焦到 input 元素
const focusInput = () => {
if (inputRef.current) {
inputRef.current.focus();
}
};
return (
<div>
<input ref={inputRef} type="text" />
<button onClick={focusInput}>Focus the input</button>
</div>
);
}
7、useImperativeHandle使用
useImperativeHandle 可以让你在使用 ref 时自定义暴露给父组件的实例值。在大多数情况下,应当避免使用 ref 这样的命令式代码。useImperativeHandle 应当与 forwardRef 一起使用:
8、Hook useMemo useCallback 的区别
useMemo、useCallback之间的区别:
1、返回值类型:
useMemo 返回的是一个记忆化的值。
useCallback 返回的是一个记忆化的函数。
2、使用场景:
useMemo 通常用于记忆计算结果,以避免在每次渲染时执行昂贵的计算。
useCallback 通常用于记忆函数,以避免在每次渲染时创建新的函数实例,从而避免子组件不必要的渲染。
3、性能优化:
useMemo 优化的是值的计算。
useCallback 优化的是函数的创建和传递。
9、useReducer:当你需要管理多个子状态或者状态更新逻辑比较复杂时,useReducer 非常有用。
const 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() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
</>
);
}
10、useImperativeHandle:是一个 React Hook,它通常与 forwardRef 一起使用,用于在父组件中直接调用子组件实例上的方法。这种方式通常用于在父组件中控制子组件的某些行为,尤其是在无法通过 props 传递回调函数的情况下。
10.1、与 forwardRef 结合使用,在子组件中使用 useImperativeHandle 来暴露特定的方法或属性给父组件。
import { TextInput } from "react-native-gesture-handler";
const FancyInput = forwardRef((props, ref) => {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
if(inputRef!=null && inputRef.current!=null){
inputRef.current.focus();
console.log("PageDemo1=FancyInput.focus()");
}
},
press: () => {
console.log("PageDemo1=FancyInput.press()");
},
// 可以暴露更多的方法或属性
}));
return <TextInput ref={inputRef} />;
});
function ParentComponent() {
const fancyInputRef = useRef();
const focusInput = () => {
fancyInputRef.current.focus();
console.log("PageDemo1=fancyInputRef.focus()");
};
return (
<>
<FancyInput ref={fancyInputRef} />
<Text onPress={focusInput}>Focus the input</Text>
</>
);
}
10.2、暴露子组件状态或方法,通过 useImperativeHandle 暴露子组件的状态或其他属性。
useImperativeHandle(ref, () => ({
getValue: () => inputRef.current.value,
// 其他状态或属性
}));
11、useLayoutEffect:与useEffect 非常相似,但是它们之间有一个关键的区别:useLayoutEffect 会在所有的 DOM 变更之后同步调用 effect。这样可以确保在浏览器进行绘制之前,你的 effect 已经执行了。
与 useEffect 的区别
useEffect会在浏览器绘制之后异步执行,而useLayoutEffect则会同步执行。useEffect的执行可能会被推迟,但useLayoutEffect的执行时机更接近于 React 的 “commit” 阶段。
useLayoutEffect(() => {
// 执行副作用操作
// ...
// 如果需要清理副作用,返回一个函数
return () => {
// 清理操作
};
}, [dependencies]); // 依赖项数组,当依赖项改变时,effect 会重新运行
12、useDeferredValue:它允许你延迟更新组件中的某些值,从而不会阻塞主线程上的更新。这在处理大量数据或者计算密集型任务时特别有用,因为它可以帮助保持应用的响应性。
13、useTransition:它允许你将更新标记为非紧急,这样它们就可以在浏览器空闲时执行,从而不会阻塞用户交互。这对于提高应用性能和响应性非常有用,尤其是在处理大量数据或复杂计算时。
14、useId:用于生成在组件树中唯一的 ID
2628

被折叠的 条评论
为什么被折叠?



