1. 函数式组件的 useState
如果要对变量进行修改,并且修改后马上要获取该值,一般会这样使用:
const [count, setCount] = useState(0);
setCount(count + 1);
console.log(count);
但是这样是拿不到立即更新后的值的,正确的方式应该是使用回调函数:
const [count, setCount] = useState(0);
setCount((value) => {
value++;
console.log(value);
return value;
});
2. 类组件的 setState
在类组件中的 setState 方法只会对涉及到的值进行修改,未涉及到的值是不会改变的。
class Demo extends Component<Props> {
constructor(props) {
super(props);
this.state = {
count: 0,
scale: 1,
}
}
change = () => {
this.setState({
count: 1
});
}
}
执行 change 方法后,scale 的值不变,而 count 的值变为 1。
且如果想要在改变后立马获取最新的值,直接在 this.setState 后获取是得不到的,因为该方法是异步的,一般通过 shouldComponentUpdate 或者 componentWillUpdate 获取。但是推荐使用回调函数:
change = () => {
this.setState({
count = 1
}, () => {
console.log(this.state.count); // 1
});
}
3. useEffct hooks
在类组件中有生命周期这个概念,且有许多生命周期的钩子函数,但在函数式组件中,是没有这个概念的,但是相应的,存在 useEffect 这个 hooks 可以实现生命周期的效果。
useEffect(() => {})
componentWillUpdate这个钩子函数在组件接收到新的 props 或者 state 但还没有 render 时被调用,且在初始化时不会被调用。useEffect(() => {})会在任意属性变动时调用,当 useState 中或者传入的 props 中属性有改变的,则会调用 useEffect 中的回调函数,也就和componentWillUpdate的执行时机类似,但是不同的地方是,useEffect(() => {})会在初始化时被调用。
useEffect(() => {}, [])
componentDidMount在第一次渲染后调用。之后组件已经生成了对应的DOM结构,可以通过this.getDOMNode()来进行访问。一般在这个方法中调用setTimeout, setInterval或者发送 AJAX 请求等操作(防止异步操作阻塞 UI)。useEffect(() => {}, [])只会在初始化时,也即是第一次渲染后调用。
useEffect(() => {}, [a, b])
该函数会在 a 和 b 变化时执行回调函数,也就是监听 a 和 b。
useEffect(() => { return () => {} }, [])
componentWillUnmount在组件从 DOM 中移除之前立刻被调用。而useEffect(() => { return () => {} }, [])会在组件被卸载时执行返回的函数,两者基本一致。
4. img 标签复用问题
通过 HTML 中img标签加载的图片,浏览器默认情况下会将其缓存起来,当我们从 JS 的代码中创建的imgDOM 对象通过设置src再去访问同一个图片时,浏览器就不会再发起新的请求,而是直接访问缓存的图片。但是由于 JS 中的imgDOM 对象设置了crossorigin,也就意味着它将要以CORS的方式请求,但缓存中的图片显然不是的,所以浏览器会直接拒绝,甚至连网络请求都没有发起,也就导致在 JS 中创建的imgDOM 对象无法显示。
解决的办法是让 HTML 中的img标签和 JS 中imgDOM 对象的访问都走跨域访问的方式:crossOrigin = "anonymous",这样既可以解决跨域访问的问题,也可以解决跨域图片在canvas中的复用问题。
5. 改变 icon 图片的颜色
我们在写页面时,常常会用到会多图标 icon,通常也会遇到主题色配置的问题,需要所有图标都根据主题色来显示不同的颜色。对此,Web 端和 React Native 端对此有着不同的解决方法。
Web 端可以使用 CSS 属性中的filter: drop-shadow(x, y, color)属性,其中x和y代表偏移量,color代表改变后的颜色,该属性可以实现将 icon 图片的颜色改为指定 color 的颜色。
React Native端可以使用 CSS 中的tinyColor: color属性,该属性可以实现将 icon 图片的颜色改为指定 color 的颜色。
需要注意的是,两种方式指定的颜色都会替换掉图片中的所有非透明区域,而基本上 icon 的图片都是由专门的 UI/UED 切出来的,所以一般非内容区域都是透明的。
6. useRef hooks
useRef 的官方定义如下:
useRefreturns a mutable ref object whose.currentproperty is initialized to the passed argument (initialValue). The returned object will persist for the full lifetime of the component.
一般情况下它可以用来获取组件实例对象或者是 DOM 对象。但除了传统的用法之外,它还可以“跨渲染周期”保存数据。换句话说,useRef在 hook 中的作用,正如官网说的,它像一个变量,类似于 this,你可以存放任何东西,而useRef每次都会返回相同的引用。
在一个组件中有什么东西可以跨渲染周期,也就是在组件被多次渲染之后依旧不变的属性?第一个想到的应该是state。没错,一个组件的state可以在多次渲染之后依旧不变。但是,state的问题在于一旦修改了它就会造成组件的重新渲染。但是useRef就可以跨越渲染周期存储数据,而且对它修改也不会引起组件渲染。
export default function MyApp(props) {
const [count, setCount] = useState(0);
const timer = useRef();
const addCount = () => {
setCount(count => count + 1);
}
useEffect(() => {
timer.current = setInterval(addCount, 1000);
}, []);
useEffect(()=>{
if(count > 10){
clearInterval(timer.current);
}
}, [count]);
return (
<>
<button onClick={addCount}>Count: {count}</button>
</>
);
}
在上面的例子中,使用ref对象的current属性来存储定时器的 ID,这样便可以在多次渲染之后依旧保存的是定时器 ID,而不会因为重新渲染导致定时器 ID 被改变,从而能正常清除定时器。
7. useMemo hooks
useMemo与useEffect类似,依赖项变化时会执行其中的回调函数。
传入 useMemo 的函数会在依赖项变化时的渲染期间执行,一般不在这个函数内部执行与渲染无关的操作,这类的操作属于 useEffect 的适用范畴,而非 useMemo。
如果没有提供依赖项数组,useEffect在每次有值改变时都会计算新的值。而当useMemo没有提供依赖项时,其会在每次渲染时都会计算新的值。