React Hooks
- useState
- useEffect
- useRef
- memo
- useCallback
- useMemo
useState
参数:初始state的值。支持传具体值或者函数。
返回值:一个数组,0:当前state的值;1:更新state的函数(类似于this.setState),支持传函数,函数的参数为当前的state值。
import React, { useState } from 'react';
function Example(props) {
// 声明一个叫 “count” 的 state 变量。
const [count, setCount] = useState(0); // 数组解构
const [count, setCount] = useState(() => {
return props.count || '0'
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
useState可以多次使用
function ExampleWithManyStates() {
// 声明多个 state 变量!
const [age, setAge] = useState(42);
const [fruit, setFruit] = useState('banana');
const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
// ...
}
set函数用法
import React, { useState } from 'react';
function Example(props) {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count => count + 1)}>
Click me
</button>
</div>
);
}
useEffect
首次渲染完成,每次更新及组件卸载时会执行,相当于把生命周期componentDidMount, componentUpdate, componentWillUnmount合并成一个勾子了。
监听第二个参数[]的state的变化,执行第一个参数,如果第二个参数不传值,默认所有state更新时都会执行effect。
useEffect在第一个参数函数主体里return相当于componentWillUnmount。return必须是一个function。
如果effect返回一个函数,当组件卸载时会执行该函数,即useEffect返回的函数相当于unmount。
import React, { useState, useEffect } from 'react';
function FriendStatus(props) {
const [isOnline, setIsOnline] = useState(null);
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
useEffect(() => {
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
};
});
if (isOnline === null) {
return 'Loading...';
}
return isOnline ? 'Online' : 'Offline';
}
当第二个参数为空数组的时候对应didMount;
当第二个数组有值时,对应的state中的值变化时,执行effect;
useEffect也可以写多个,
function ExampleWithManyStates() {
// 声明多个 state 变量!
const [age, setAge] = useState(42);
const [fruit, setFruit] = useState('banana');
useEffect(() => {
console.log(age)
}, [age]) // 只有在age有变化时才执行effect
}
useRef
useRef返回一个可变的ref对象,获取最新的state,返回值是一个对象:{current: 当前变量的值}。
返回的ref对象在组件的整个生命周期内保持不变。
用法1:类似于refs的用法,命令式的访问子组件。
function TextInputWithFocusButton() {
const inputEl = useRef(null); // {current: input元素}
const onButtonClick = () => {
// `current` 指向已挂载到 DOM 上的文本输入元素
// 使输入框获得焦点
inputEl.current.focus();
}
return (
<div>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</div>
)
}
用法2:获取最新的state
import React, { useEffect, useState, useRef } from "react";
function Demo(){
const numRef = useRef();
const [num, changeNum] = useState(1);
function submit(){
console.log(`现在的数字是: ${numRef.current}`)
}
useEffect(() => {
numRef.current = num;
});
}
memo
简单的子组件可以用memo包裹来节约计算性能,父组件重新render时,子组件不会跟着重新渲染;
memo的功能类似PureComponent。
import React, { useState, memo } from 'react';
const Img = (props) => {
console.log('Img render');
return <p>img component: {props.imageData}</p>;
};
const ImgMemo = memo(Img);
export default () => {
const [count, setCount] = useState(1);
const [imageData, setImageData] = useState('src1');
const addCount = () => {
setCount(count + 1);
};
return (
<div>
<p onClick={addCount}>click {count}</p>
<ImgMemo imageData={imageData} />
</div>
);
};
useCallback
当父组件向子组件传递一个函数作为属性时,即使触发函数子组件没有变化时子组件也会重新渲染;
原因:向子组件传递一个非基本类型的函数作为属性时,父组件每次重新渲染,属性值都会被重新赋值,属性值发生变化,子组件就会重新渲染。
useCallback就是保证父组件在初始化时创建一个对象,当useCallback的依赖变量没有变化时,改对象就不会发生变化。
useCallback是在父组件传递函数作为属性给子组件的时候用的。
import React, { useState, memo, useCallback } from 'react';
const Img = (props) => {
console.log('Img render');
return <p>img component: {props.imageData}</p>;
};
const ImgMemo = memo(Img);
export default () => {
const [count, setCount] = useState(1);
const [imageData, setImageData] = useState('src1');
const addCount = () => {
setCount(count + 1);
};
const onImgClick = useCallback(() => {
setImageData('src2');
}, []);
return (
<div>
<p onClick={addCount}>click {count}</p>
<ImgMemo imageData={imageData} onImgClick={onImgClick} />
</div>
);
};
useMemo
父组件向子组件传一个对象数据类型的属性时,如果在子组件中引用该对象属性的字段没有发生变化时,使用useMemo减少不必要的渲染。
当useMemo依赖的变量发生变化时才会重新渲染。
import React, { useState, memo, useMemo } from 'react';
const Img = (props) => {
console.log('Img render');
return <p>img component: {props.imageData.a}</p>;
};
const ImgMemo = memo(Img);
export default () => {
const [count, setCount] = useState(1);
const [imageData, setImageData] = useState({
a: '1'
});
const addCount = () => {
setCount(count + 1);
setImageData({
...imageData,
b: new Date()
});
};
const imageDataMemo = useMemo(() => {
return imageData
}, [imageData.a])
return (
<div>
<p onClick={addCount}>click {count}</p>
<ImgMemo imageData={imageDataMemo} />
</div>
);
};
- 函数名首字母一定要大写
- 如果useEffect在第一个参数里存在定时器记得在return的时候清除掉,不清除掉会报错