React.js 学习笔记(2)
函数型组件,钩子函数
React 最新的趋势是使用函数型组件来代替类组件。
与类组件相比,函数型组件缺少状态,生命周期等必要的元素。
React 通过引入钩子函数来解决这些问题。
useState
在函数型组件中定义状态值需要使用 useState 钩子函数。
改变组件的状态值会触发组件的更新,即组件会被重新渲染。
useState 函数的参数为该状态值的初值。
useState 函数的返回值中可以提取该状态值的 getter 和 setter。
const [count, setCount] = useState(0);
这里定义一个状态,初值为 0。
getter 为 count,类型为 int,可以提取当前状态值。
setter 为 setCount。可以设置状态的值。
setCount 的参数可以是 int,用于同步更新,也可以是一个回调函数,用于异步更新。
count
setCount(count + 1);
setCount(n => n + 1);
useEffect
在函数型组件中执行副作用需要使用 useEffect 钩子函数。
useEffect 大致有三种功能。
- 组件更新后触发副作用
- 在组件再次更新或卸载之前执行对副作用的清理操作
- 通过监听某些依赖项来控制副作用和清理操作被执行的时机
useEffect 有两个参数。
useEffect 的第一个参数为回调函数,可以在其中定义需要触发的副作用。
useEffect 的回调函数参数如果有返回值,可以返回一个回调函数,在其中定义需要执行的清理操作。
useEffect 的第二个参数为需要监听的依赖项数组。这里的依赖项是指组件的状态值。
useEffect 的第二个参数不存在时,组件每次更新后都会触发副作用,在组件再次更新或卸载之前都会执行清理操作。
useEffect 的第二个参数为空数组时,只有在组件初始化后才会触发副作用,只有在组件卸载之前才会执行清理操作。
useEffect 的第二个参数为包含某些依赖项的非空数组时,只有这些依赖项的值发生变化后组件才会执行副作用和清理操作。这里变化的依据是引用相等性。
useEffect 所定义的回调函数和清理操作至少会被执行一次。
// 依赖项数组不存在,每次组件更新都会触发副作用
useEffect(() => {
// 副作用
});
// 依赖项数组为空,组件初始化后执行副作用,组件卸载前执行清理操作
useEffect(() => {
// 副作用
const id = setInterval(callback, 1000);
return () => {
// 清理操作
clearInterval(id);
};
}, []);
// 依赖项数组不为空,只有当其中的对象发生变化时才会触发副作用
useEffect(() => {
// 副作用
}, [a, b, c]);
useReducer
useReducer 钩子函数是 useState 的增强版,该函数为状态值的管理提供了更强的控制能力。
useReducer 有两个参数,reducer 回调函数和状态的初始值。
reducer 回调函数有两个参数,分别是当前的状态值和 action 参数。
reducer 回调函数的 action 参数可以不存在,可以是指定操作类型的字符串,也可以是包含操作类型和操作负载的复杂对象。
reducer 回调函数依据 action 参数的值执行相应的操作并返回新的状态值。
useReducer 函数的返回值中可以提取该状态值的 getter 和 dispatch。
状态值的 dispatch 函数带有一个 action 参数。
通过调用 dispatch 函数可以将当前状态值以及 action 参数传递给 reducer 回调函数,执行相应的操作并用返回值来更新状态值。
// action 参数不存在
const [state, dispatch] = useReducer(x => x + 1, 0);
// dispatch 函数被调用,state 无条件递增
dispatch(); // state = 1
const [, forceUpdate] = useReducer(x => x + 1, 0);
// forceUpdate 函数被调用,由于不知名状态值被更新,组件被强制更新
forceUpdate();
// action 参数是简单的操作类型
const reducer = (state, action) => {
if (action === '++') return state + 1;
if (action === '--') return state - 1;
return state;
}
const [state, dispatch] = useReducer(reducer, 0);
// dispatch 函数被调用,根据操作类型 state 递增或递减
dispatch('++'); // state = 1
dispatch('--'); // state = 0
// action 参数是个对象,内含操作类型和操作负载(操作所涉及的参数)
const reducer = (state, action) => {
if (action.type === '+') return state + action.payload;
if (action.type === '-') return state - action.payload;
return state;
}
const [state, dispatch] = useReducer(reducer, 0);
// dispatch 函数被调用,根据操作类型 state 增加或减少操作负载所对应的数值
dispatch({type: '+', payload: 2}); // state = 2
dispatch({type: '-', payload: 3}); // state = -1
useRef
useRef 钩子函数用于引用一个不参与组件渲染的值。
useRef 函数的参数为引用的初始值。
useRef 函数返回所创建的引用,该引用有一个 current 字段,用于读取或设置引用的当前值。
useRef 所创建的引用可以在组件的多次渲染期间保持当前值不变。
改变引用的当前值不会触发组件的更新。
// ref 引用不参与组件的渲染
const ref = useRef(0); // ref.current = 0
// 改变 ref 引用的值不会触发组件的更新
ref.current++; // ref.current = 1
useRef 函数可以用于获取 DOM 元素的引用
// inputRef 用于保存输入框组件的引用
const inputRef = useRef(null);
// 将输入框的背景色设置为黄色
inputRef.current.style.background = "yellow"
// 获取输入框组件的引用
<input type="text" ref={inputRef} />
useRef 函数所创建的引用可用于存放 timer interval 的 id
useMemo
在多次渲染期间缓存计算结果可以使用 useMemo 钩子函数。
useMemo 可用于计算属性,也可用于防止某些耗时较长的操作反复执行。
useMemo 有两个参数。
useMemo 的第一个参数是用于计算的 calculate 回调函数。
calculate 回调函数没有参数,函数体内计算并返回需要缓存的值。
useMemo 的第二个参数是需要监听的依赖项数组。这里的依赖项是指组件的状态值。
首次计算或者依赖项数组中的依赖项发生变化时 useMemo 返回计算结果。
依赖项数组没有变化时 useMemo 返回之前缓存的值。
const result = useMemo(() => slowFunction(), []);
const result = useMemo(() => cal(count), [count]);