Reacthooks的优缺点详解
⽬录
前⾔
优点:
缺点:
⼀、响应式的useEffect
reacthooks理解⼆、状态不同步
怎么避免react hooks的常见问题
前⾔
Hook 是 React 16.8 的新增特性。它是完全可选的,并且100%向后兼容。它可以让你使⽤函数组件的⽅式,运⽤类组件以及react 其他的⼀些特性,⽐如管理状态、⽣命周期钩⼦等。从概念上讲,React 组件⼀直更像是函数。⽽ Hook 则拥抱了函数,同时也没有牺牲 React 的精神原则。
优点:
1、代码可读性更强,原本同⼀块功能的代码逻辑被拆分在了不同的⽣命周期函数中,容易使开发者不利于维护和迭代,通过React Hooks 可以将功能代码聚合,⽅便阅读维护。例如,每个⽣命周期中常常会包含⼀些不相关的逻辑。⼀般我们都会在componentDidMount 和 componentDidUpdate 中获取数据。但是,同⼀个 componentDidMount 中可能也包含很多其它的逻辑,如设置事件监听,⽽之后需在 componentWillUnmount 中清除。相互关联且需要对照修改的代码被进⾏了拆分,⽽完全不相关的代码却在同⼀个⽅法中组合在⼀起。如此很容易产⽣ bug,并且导致逻辑不⼀致。
2、组件树层级变浅。在原本的代码中,我们经常使⽤ HOC/render props 等⽅式来复⽤组件的状态,增强功能等,⽆疑增加了组件树层数及渲染,在 React DevTools 中观察过 React 应⽤,你会发现由 providers,consumers,⾼阶组件,render props 等其他抽象层组成的组件会形成“嵌套地狱”。⽽在 React Hooks 中,这些功能都可以通过强⼤的⾃定义的 Hooks 来实现。
3、不⽤再去考虑 this 的指向问题。在类组件中,你必须去理解 JavaScript 中 this 的⼯作⽅式。
缺点:
⼀、响应式的useEffect
写函数组件时,你不得不改变⼀些写法习惯。你必须清楚代码中useEffect和useCallback的“依赖项数组”的改变时机。有时候,你的useEffect依赖某个函数的不可变性,这个函数的不可变性⼜依赖于另⼀个函数的不可变性,这样便形成了⼀条依赖链。⼀旦这条依赖链的某个节点意外地被改变了,你的useEffect就被意外地触发了,如果你的useEffect是幂等的操作,可能带来的是性能层次的问题,如果是⾮幂等,那就糟糕了。
所以,对⽐componentDidmount和componentDidUpdate,useEffect带来的⼼智负担更⼤。
⼆、状态不同步
函数的运⾏是独⽴的,每个函数都有⼀份独⽴的作⽤域。函数的变量是保存在运⾏时的作⽤域⾥⾯,当我们有异步操作的时候,经常会碰到异步回调的变量引⽤是之前的,也就是旧的(这⾥也可以理解成闭包)。⽐如下⾯的⼀个例⼦:
import React, { useState } from "react";
const Counter = () => {
const [counter, setCounter] = useState(0);
const onAlertButtonClick = () => {
setTimeout(() => {
alert("Value: " + counter);
}, 3000);
};
return (
<div>
<p>You clicked {counter} times.</p>
<button onClick={() => setCounter(counter + 1)}>Click me</button>
<button onClick={onAlertButtonClick}>
Show me the value in 3 seconds
</button>
</div>
);
};
export default Counter;
当你点击Show me the value in 3 seconds的后,紧接着点击Click me使得counter的值从0变成1。三秒后,定时器触发,但alert出来的是0(旧值),但我们希望的结果是当前的状态1。
这个问题在class component不会出现,因为class component的属性和⽅法都存放在⼀个instance上,调⽤⽅式是:和hod()。因为每次都是从⼀个不变的instance上进⾏取值,所以不存在引⽤是旧的问题。
其实解决这个hooks的问题也可以参照类的instance。⽤useRef返回的immutable RefObject(current属性是可变的)来保存state,然后取值⽅式从counter变成了: counterRef.current。如下:
import React, { useState, useRef, useEffect } from "react";
const Counter = () => {
const [counter, setCounter] = useState(0);
const counterRef = useRef(counter);
const onAlertButtonClick = () => {
setTimeout(() => {
alert("Value: " + counterRef.current);
}, 3000);
};
useEffect(() => {
counterRef.current = counter;
});
return (
<div>
<p>You clicked {counter} times.</p>
<button onClick={() => setCounter(counter + 1)}>Click me</button>
<button onClick={onAlertButtonClick}>
Show me the value in 3 seconds
</button>
</div>
);
};
export default Counter;
结果我们所期待,alert的是当前的值1。
怎么避免react hooks的常见问题
不要在useEffect⾥⾯写太多的依赖项,划分这些依赖项成多个单⼀功能的useEffect。其实这点是遵循了软件设计的“单⼀职责模式”。
如果你碰到状态不同步的问题,可以考虑下⼿动传递参数到函数。如:
// showCount的count来⾃⽗级作⽤域
const [count,setCount] = useState(xxx);
function showCount(){ console.log(count) }
// showCount的count来⾃参数
const [count,setCount] = useState(xxx);
function showCount(c){ console.log(c) }
但这个也只能解决⼀部分问题,很多时候你不得不使⽤上述的useRef⽅案。
3. 重视eslint-plugin-react-hooks插件的警告。
4. 复杂业务的时候,使⽤Component代替hooks。
以上就是React hooks的优缺点详解的详细内容,更多关于React hooks的优缺点的资料请关注其它相关⽂章!