React Hooks的理解
<p><img src="https://img2020.cnblogs.com/blog/1161361/202108/1161361-20210806155527518-1719617132.png" alt="" loading="lazy"></p><p> </p>
<p> </p>
<h2 data-tool="mdnice编辑器">一、是什么</h2>
<p data-tool="mdnice编辑器"><code>Hook</code> 是 React 16.8 的新增特性。它可以让你在不编写 <code>class</code> 的情况下使用 <code>state</code> 以及其他的 <code>React</code> 特性</p>
<p data-tool="mdnice编辑器">至于为什么引入<code>hook</code>,官方给出的动机是解决长时间使用和维护<code>react</code>过程中常遇到的问题,例如:</p>
<ul class="list-paddingleft-2" data-tool="mdnice编辑器">
<li>难以重用和共享组件中的与状态相关的逻辑</li>
<li>逻辑复杂的组件难以开发与维护,当我们的组件需要处理多个互不相关的 local state 时,每个生命周期函数中可能会包含着各种互不相关的逻辑在里面</li>
<li>类组件中的this增加学习成本,类组件在基于现有工具的优化上存在些许问题</li>
<li>由于业务变动,函数组件不得不改为类组件等等</li>
</ul>
<p data-tool="mdnice编辑器">在以前,函数组件也被称为无状态的组件,只负责渲染的一些工作</p>
<p data-tool="mdnice编辑器">因此,现在的函数组件也可以是有状态的组件,内部也可以维护自身的状态以及做一些逻辑方面的处理</p>
<h2 data-tool="mdnice编辑器">二、有哪些</h2>
<p data-tool="mdnice编辑器">上面讲到,<code>Hooks</code>让我们的函数组件拥有了类组件的特性,例如组件内的状态、生命周期</p>
<p data-tool="mdnice编辑器">最常见的<code>hooks</code>有如下:</p>
<ul class="list-paddingleft-2" data-tool="mdnice编辑器">
<li>useState</li>
<li>useEffect</li>
<li>其他</li>
</ul>
<h3 data-tool="mdnice编辑器">useState</h3>
<p data-tool="mdnice编辑器">首先给出一个例子,如下:</p>
<div class="cnblogs_code">
<pre>import React, { useState } from 'react'<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> Example() {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 声明一个叫 "count" 的 state 变量</span>
const = useState(0<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (
</span><div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}><span style="color: rgba(0, 0, 0, 1)">
Click me
</span></button>
</div>
<span style="color: rgba(0, 0, 0, 1)">);
}</span></pre>
</div>
<p data-tool="mdnice编辑器">在函数组件中通过<code>useState</code>实现函数内部维护<code>state</code>,参数为<code>state</code>默认的值,返回值是一个数组,第一个值为当前的<code>state</code>,第二个值为更新<code>state</code>的函数</p>
<p data-tool="mdnice编辑器">该函数组件等价于的类组件如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">class Example extends React.Component {
constructor(props) {
super(props);
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.state =<span style="color: rgba(0, 0, 0, 1)"> {
count: </span>0<span style="color: rgba(0, 0, 0, 1)">
};
}
render() {
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (
</span><div>
<p>You clicked {<span style="color: rgba(0, 0, 255, 1)">this</span>.state.count} times</p>
<button onClick={() => <span style="color: rgba(0, 0, 255, 1)">this</span>.setState({ count: <span style="color: rgba(0, 0, 255, 1)">this</span>.state.count + 1 })}><span style="color: rgba(0, 0, 0, 1)">
Click me
</span></button>
</div>
<span style="color: rgba(0, 0, 0, 1)"> );
}
}</span></pre>
</div>
<p data-tool="mdnice编辑器">从上述两种代码分析,可以看出两者区别:</p>
<ul class="list-paddingleft-2" data-tool="mdnice编辑器">
<li>
<p>state声明方式:在函数组件中通过 useState 直接获取,类组件通过constructor 构造函数中设置</p>
</li>
<li>
<p>state读取方式:在函数组件中直接使用变量,类组件通过<code>this.state.count</code>的方式获取</p>
</li>
<li>
<p>state更新方式:在函数组件中通过 setCount 更新,类组件通过this.setState()</p>
</li>
</ul>
<p data-tool="mdnice编辑器">总的来讲,useState 使用起来更为简洁,减少了<code>this</code>指向不明确的情况</p>
<h3 data-tool="mdnice编辑器">useEffect</h3>
<p data-tool="mdnice编辑器"><code>useEffect</code>可以让我们在函数组件中进行一些带有副作用的操作</p>
<p data-tool="mdnice编辑器">同样给出一个计时器示例:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">class Example extends React.Component {
constructor(props) {
super(props);
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.state =<span style="color: rgba(0, 0, 0, 1)"> {
count: </span>0<span style="color: rgba(0, 0, 0, 1)">
};
}
componentDidMount() {
document.title </span>= `You clicked ${<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.state.count} times`;
}
componentDidUpdate() {
document.title </span>= `You clicked ${<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.state.count} times`;
}
render() {
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (
</span><div>
<p>You clicked {<span style="color: rgba(0, 0, 255, 1)">this</span>.state.count} times</p>
<button onClick={() => <span style="color: rgba(0, 0, 255, 1)">this</span>.setState({ count: <span style="color: rgba(0, 0, 255, 1)">this</span>.state.count + 1 })}><span style="color: rgba(0, 0, 0, 1)">
Click me
</span></button>
</div>
<span style="color: rgba(0, 0, 0, 1)"> );
}
}</span></pre>
</div>
<p data-tool="mdnice编辑器">从上面可以看见,组件在加载和更新阶段都执行同样操作</p>
<p data-tool="mdnice编辑器">而如果使用<code>useEffect</code>后,则能够将相同的逻辑抽离出来,这是类组件不具备的方法</p>
<p data-tool="mdnice编辑器">对应的<code>useEffect</code>示例如下:</p>
<div class="cnblogs_code">
<pre>import React, { useState, useEffect } from 'react'<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> Example() {
const </span>= useState(0<span style="color: rgba(0, 0, 0, 1)">);
useEffect(() </span>=> { document.title =<span style="color: rgba(0, 0, 0, 1)"> `You clicked ${count} times`;});
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (
</span><div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}><span style="color: rgba(0, 0, 0, 1)">
Click me
</span></button>
</div>
<span style="color: rgba(0, 0, 0, 1)">);
}</span></pre>
</div>
<p data-tool="mdnice编辑器"><code>useEffect</code>第一个参数接受一个回调函数,默认情况下,<code>useEffect</code>会在第一次渲染和更新之后都会执行,相当于在<code>componentDidMount</code>和<code>componentDidUpdate</code>两个生命周期函数中执行回调</p>
<p data-tool="mdnice编辑器">如果某些特定值在两次重渲染之间没有发生变化,你可以跳过对 effect 的调用,这时候只需要传入第二个参数,如下:</p>
<div class="cnblogs_code">
<pre>useEffect(() =><span style="color: rgba(0, 0, 0, 1)"> {
document.title </span>=<span style="color: rgba(0, 0, 0, 1)"> `You clicked ${count} times`;
}, ); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 仅在 count 更改时更新</span></pre>
</div>
<p data-tool="mdnice编辑器">上述传入第二个参数后,如果 <code>count</code> 的值是 <code>5</code>,而且我们的组件重渲染的时候 <code>count</code> 还是等于 <code>5</code>,React 将对前一次渲染的 <code></code> 和后一次渲染的 <code></code> 进行比较,如果是相等则跳过<code>effects</code>执行</p>
<p data-tool="mdnice编辑器">回调函数中可以返回一个清除函数,这是<code>effect</code>可选的清除机制,相当于类组件中<code>componentwillUnmount</code>生命周期函数,可做一些清除副作用的操作,如下:</p>
<div class="cnblogs_code">
<pre>useEffect(() =><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
</span><span style="color: rgba(0, 0, 255, 1)">return</span> () =><span style="color: rgba(0, 0, 0, 1)"> {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
};
});</span></pre>
</div>
<p data-tool="mdnice编辑器">所以, <code>useEffect</code>相当于<code>componentDidMount</code>,<code>componentDidUpdate</code> 和 <code>componentWillUnmount</code> 这三个生命周期函数的组合</p>
<h3 data-tool="mdnice编辑器">其它 hooks</h3>
<p data-tool="mdnice编辑器">在组件通信过程中可以使用<code>useContext</code>,<code>refs</code>学习中我们也用到了<code>useRef</code>获取<code>DOM</code>结构......</p>
<p data-tool="mdnice编辑器">还有很多额外的<code>hooks</code>,如:</p>
<ul class="list-paddingleft-2" data-tool="mdnice编辑器">
<li>useReducer</li>
<li>useCallback</li>
<li>useMemo</li>
<li>useRef</li>
</ul>
<h2 data-tool="mdnice编辑器">三、解决什么</h2>
<p data-tool="mdnice编辑器">通过对上面的初步认识,可以看到<code>hooks</code>能够更容易解决状态相关的重用的问题:</p>
<ul class="list-paddingleft-2" data-tool="mdnice编辑器">
<li>
<p>每调用useHook一次都会生成一份独立的状态</p>
</li>
<li>
<p>通过自定义hook能够更好的封装我们的功能</p>
</li>
</ul>
<p data-tool="mdnice编辑器">编写<code>hooks</code>为函数式编程,每个功能都包裹在函数中,整体风格更清爽,更优雅</p>
<p data-tool="mdnice编辑器"><code>hooks</code>的出现,使函数组件的功能得到了扩充,拥有了类组件相似的功能,在我们日常使用中,使用<code>hooks</code>能够解决大多数问题,并且还拥有代码复用机制,因此优先考虑<code>hooks</code></p>
</div>
<div id="MySignature" role="contentinfo">
<p>本文来自博客园,作者:喆星高照,转载请注明原文链接:https://www.cnblogs.com/houxianzhou/p/15108991.html</p><br><br>
来源:https://www.cnblogs.com/houxianzhou/p/15108991.html
頁:
[1]