干货满满-原来这才是hooks-React Hooks使用心得
<h2 id="%E5%BA%8F%E8%A8%80" class="mume-header">序言</h2><pre class="language-text"><span style="font-size: 14px">---最后有招聘信息哦~<br><br>React是一个库,它不是一个框架。用于构建用户界面的Javascript库。这里大家需要认识这一点。react的核心在于它仅仅是考虑了如何将dom节点更快更好更<br>合适的渲染到浏览器中。它本身提供的涉及框架的理念是不多的。class组件是如此,hooks组件也是如此。</span></pre>
<h2 id="classcomponent" class="mume-header">ClassComponent</h2>
<p>我们先回顾一下,这是一个react的class组件:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">class HelloMessage 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)"> {
num: </span>1<span style="color: rgba(0, 0, 0, 1)">
}
}
componentDidMount () {
alert(</span>'mounted!'<span style="color: rgba(0, 0, 0, 1)">)
}
addNum () {
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.setState({
num: </span><span style="color: rgba(0, 0, 255, 1)">this</span>.state.num + 1<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><span style="color: rgba(0, 0, 0, 1)">
Hello {</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.props.name}
</span></div>
<span style="color: rgba(0, 0, 0, 1)"> );
}
}
ReactDOM.render(
</span><HelloMessage name="Taylor" />,
document.getElementById('hello-example'<span style="color: rgba(0, 0, 0, 1)">)
);</span></pre>
</div>
<p> </p>
<p>它包含了:</p>
<ul>
<li>props</li>
<li>state</li>
<li>setState</li>
<li>render</li>
<li>生命周期</li>
</ul>
<p>再来看看class组件中比较特殊的,具有代表意义的东西:</p>
<p>1、setState</p>
<p><br>通过对象更新的方式更新组件状态,react通过diff算法自动更新dom</p>
<p>2、Ref</p>
<p><br>一个可以用来访问dom对象的东西</p>
<p>3、this</p>
<p><br>classComponent中通过this访问各种数据/方法</p>
<p><br>4、生命周期</p>
<p><img src="https://img2020.cnblogs.com/blog/893115/202103/893115-20210304185049032-1447138251.png" alt="" width="817" height="844" loading="lazy"></p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<h3>class组件存在的问题</h3>
<p>* 逻辑分散<br>* 数据分散<br>* 组件拆分繁琐,state树往往较大</p>
<p>我们构建React组件的方式与组件的生命周期是耦合的。这一鸿沟顺理成章的迫使整个组件中散布着相关的逻辑。在下面的示例中,我们可以清楚地了解到这一点。有三个的方法componentDidMount、componentDidUpdate<em id="__mceDel">和updateRepos</em><em id="__mceDel"><em id="__mceDel">来完成相同的任务——使repos与任何props.id同步。</em></em></p>
<p class="sync-line" data-line="65"> </p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">componentDidMount () {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.updateRepos(<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.props.id)
}
componentDidUpdate (prevProps) {
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (prevProps.id !== <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.props.id) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.updateRepos(<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.props.id)
}
}
updateRepos </span>= (id) =><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.setState({ loading: <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)"> })
fetchRepos(id)
.then((repos) </span>=> <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.setState({
repos,
loading: </span><span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">
}))
}</span></pre>
</div>
<p> </p>
<p>为了解决这个问题(它是一系列问题的其中之一,这里只简单举例),react创造了一个全新的方式来解决,那就是hooks。</p>
<p class="sync-line" data-line="85"> </p>
<h2>FunctionalComponent</h2>
<p>hooks的目的是让大家在一定程度上 <strong>“使用函数的想法去开发组件”</strong> 。<br>纯函数组件、高阶组件<br><strong>先粗浅理解函数式</strong></p>
<p><img src="https://img2020.cnblogs.com/blog/893115/202103/893115-20210304185312030-1323506034.png" alt="" width="145" height="71" loading="lazy"></p>
<p><br>主要思想是把运算过程尽量写成一系列嵌套的函数调用。举例来说,现在有这样一个数学表达式:</p>
<div class="cnblogs_code">
<pre>(1 + 2) * 3 - 4</pre>
</div>
<p> </p>
<p>传统的过程式编程,可能这样写:</p>
<p class="sync-line" data-line="94"> </p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">var</span> a = 1 + 2<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">var</span> b = a * 3<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">var</span> c = b - 4;</pre>
</div>
<p> </p>
<p>函数式编程要求使用函数,我们可以把运算过程定义为不同的函数,然后写成下面这样:</p>
<p class="sync-line" data-line="102"> </p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">var</span> result = subtract(multiply(add(1,2), 3), 4);</pre>
</div>
<p> </p>
<p><strong>函数式的特点</strong></p>
<ol>
<li>
<p>函数是"第一等公民"</p>
</li>
<li>
<p>只用"表达式",不用"语句"</p>
</li>
</ol>
<p>"表达式"(expression)是一个单纯的运算过程,总是有返回值;"语句"(statement)是执行某种操作,没有返回值。函数式编程要求,只使用表达式,不使用语句。也就是说,每一步都是单纯的运算,而且都有返回值。</p>
<p>原因是函数式编程的开发动机,一开始就是为了处理运算(computation),不考虑系统的读写(I/O)。"语句"属于对系统的读写操作,所以就被排斥在外。</p>
<p>当然,实际应用中,不做I/O是不可能的。因此,编程过程中,函数式编程只要求把I/O限制到最小,不要有不必要的读写行为,保持计算过程的单纯性。</p>
<p><strong>纯函数组件</strong><br>FunctionComponent:</p>
<p>满足“不修改状态”, “引用透明” ,“组件一等公民”, “没有副作用”, “表达式</p>
<p> </p>
<p> </p>
<p> <img src="https://img2020.cnblogs.com/blog/893115/202103/893115-20210304185249615-836090381.png" alt="" width="461" height="150" loading="lazy"></p>
<p> </p>
<p> </p>
<p> </p>
<p><strong>高阶组件</strong><br>higherOrderComponent(高阶组件):</p>
<p>传入一个组件,返回另一个包装组件,向其注入数据、逻辑,达到拆分组件的目的<br><img src="https://img2020.cnblogs.com/blog/893115/202103/893115-20210304185342650-420885285.png" alt="" width="598" height="185" loading="lazy"></p>
<p> </p>
<p> </p>
<p class="sync-line" data-line="130"> </p>
<div class="cnblogs_code">
<pre>import * as React from 'react'<span style="color: rgba(0, 0, 0, 1)">;
export </span><span style="color: rgba(0, 0, 255, 1)">default</span> <span style="color: rgba(0, 0, 255, 1)">function</span><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)"> (
ComponentA({ Com: ComponentB })
)
}
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> ComponentA (
{ Com }: { Com: React.FunctionComponent</span><any><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>
<Com style={{ color: 'red' }} />
</div>
<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)"> ComponentB ({ style }: {
style: any
}) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (
</span><div style={style}>hello high order component</div>
<span style="color: rgba(0, 0, 0, 1)"> )
}</span></pre>
</div>
<p> </p>
<p class="sync-line" data-line="159"> </p>
<h2 id="hooks%E4%B8%8E%E5%AE%9E%E8%B7%B5" class="mume-header">Hooks与实践</h2>
<p>Hooks你可以理解为具备class组件功能的函数式组件——至少它的理想是函数式</p>
<p><strong>HooksAPI-</strong><em id="__mceDel"><strong>今天的重点不在这里,这里不去细细讲它</strong></em></p>
<div class="cnblogs_code">
<pre>1<span style="color: rgba(0, 0, 0, 1)">、useState
</span>2<span style="color: rgba(0, 0, 0, 1)">、useReducer
</span>3<span style="color: rgba(0, 0, 0, 1)">、useEffect
</span>4<span style="color: rgba(0, 0, 0, 1)">、useLayoutEffect
</span>5<span style="color: rgba(0, 0, 0, 1)">、useMemo
</span>6<span style="color: rgba(0, 0, 0, 1)">、useCallback
</span>7<span style="color: rgba(0, 0, 0, 1)">、useContext
</span>8、useRef</pre>
</div>
<p> </p>
<p><strong>Hooks基本规则</strong><br>1、只在最顶层使用 Hook(<strong>why? 后文提到</strong>)</p>
<p>不要在循环,条件或嵌套函数中调用 Hook, 确保总是在你的 React 函数的最顶层调用他们。遵守这条规则,你就能确保 Hook 在每一次渲染中都按照同样的顺序被调用。这让 React 能够在多次的 useState 和 useEffect 调用之间保持 hook 状态的正确。(如果你对此感到好奇,在下面会有更深入的解释。)</p>
<p>2、只在 React 函数中调用 Hook<br>3、严格控制函数的行数(相信我,超过500行的函数,任何人都会头秃)<br><strong>hooks生命周期对应</strong></p>
<p class="sync-line" data-line="188"> </p>
<div class="cnblogs_code">
<pre>export <span style="color: rgba(0, 0, 255, 1)">default</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> HooksComponent () {
const [ date, setDate ] </span>= React.useState(<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Date());
const div </span>= React.useRef(<span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">);
const tick </span>= React.useCallback(() =><span style="color: rgba(0, 0, 0, 1)"> {
setDate(</span><span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Date());
}, [])
const color </span>= React.useCallback(() =><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (div.current) {
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (div.current.style.cssText.indexOf('red') > -1<span style="color: rgba(0, 0, 0, 1)">) {
div.current.style.cssText </span>= 'background: green;'<span style="color: rgba(0, 0, 0, 1)">
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
div.current.style.cssText </span>= 'background: red;'<span style="color: rgba(0, 0, 0, 1)">
}
}
}, [ div ]);
const timerID </span>= React.useMemo(() =><span style="color: rgba(0, 0, 0, 1)"> {
console.log(</span>'==组件是否更新(概念有区别)=='<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)"> setInterval(
() </span>=><span style="color: rgba(0, 0, 0, 1)"> tick(),
</span>1000<span style="color: rgba(0, 0, 0, 1)">
);
}, [ div ])
React.useEffect(() </span>=><span style="color: rgba(0, 0, 0, 1)"> {
console.log(</span>'==组件加载完成=='<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)"> {
console.log(</span>'==组件将要销毁=='<span style="color: rgba(0, 0, 0, 1)">)
clearInterval(timerID);
}
}, [])
React.useEffect(() </span>=><span style="color: rgba(0, 0, 0, 1)"> {
console.log(</span>'==组件更新完成=='<span style="color: rgba(0, 0, 0, 1)">)
color();
}, [ date ])
console.log(</span>'==组件将要加载=='<span style="color: rgba(0, 0, 0, 1)">)
console.log(</span>'==组件获取新的props=='<span style="color: rgba(0, 0, 0, 1)">)
console.log(</span>'==组件将要更新=='<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><DemoComponent />
<span style="color: rgba(0, 0, 0, 1)"> )
}</span></pre>
</div>
<p> </p>
<p><img src="https://img2020.cnblogs.com/blog/893115/202103/893115-20210304185502767-553587824.png" alt="" width="752" height="571" loading="lazy"></p>
<p> </p>
<p> </p>
<p class="sync-line" data-line="240"> </p>
<h2 id="hooks%E5%8E%9F%E7%90%86demo%E5%AE%9E%E7%8E%B0" class="mume-header">Hooks原理demo实现</h2>
<p>实现文件:</p>
<p class="sync-line" data-line="243"> </p>
<div class="cnblogs_code">
<pre>import * as React from 'react'<span style="color: rgba(0, 0, 0, 1)">;
type State </span>=<span style="color: rgba(0, 0, 0, 1)"> {
: any
}
export type Reducer </span>= (state: State, action: string) =><span style="color: rgba(0, 0, 0, 1)"> State;
export type UseReducer </span>= <span style="color: rgba(0, 0, 255, 1)">typeof</span><span style="color: rgba(0, 0, 0, 1)"> demoReducer;
type Queue</span><T> =<span style="color: rgba(0, 0, 0, 1)"> {
root: Queue</span><T> | <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">,
next: Queue</span><T> | <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">,
prev: Queue</span><T> | <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">,
value: T,
index: number
}
const memo: Queue</span><State>[] =<span style="color: rgba(0, 0, 0, 1)"> [];
let index </span>= 0<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">function</span> demoReducer (reducer: Reducer, initalState?: State, update?: () => <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)">) : any[] {
let has </span>= !!<span style="color: rgba(0, 0, 0, 1)">memo;
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">memo) {
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (index === 0<span style="color: rgba(0, 0, 0, 1)">) {
memo[</span>0] = GeQueue<State><span style="color: rgba(0, 0, 0, 1)">(initalState, index);
memo[</span>0].root =memo;
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
memo </span>= GeQueue<State><span style="color: rgba(0, 0, 0, 1)">(initalState, index);
memo.root </span>=memo;
memo.prev </span>= memo;
memo.next =<span style="color: rgba(0, 0, 0, 1)"> memo;
}
index </span>= index + 1<span style="color: rgba(0, 0, 0, 1)">;
}
let state;
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (has) {
state </span>=<span style="color: rgba(0, 0, 0, 1)"> memo.value;
index </span>= index + 1<span style="color: rgba(0, 0, 0, 1)">;
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
state </span>= memo.value;
}
let bindex </span>=<span style="color: rgba(0, 0, 0, 1)"> index;
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> [
state,
(action: string) </span>=><span style="color: rgba(0, 0, 0, 1)"> {
memo.value = reducer(memo.value, action)
update();
}
]
}
</span><span style="color: rgba(0, 0, 255, 1)">function</span> GeQueue<T>(value: T, index: number): Queue<T><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)"> {
root: </span><span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">,
prev: </span><span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">,
next: </span><span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">,
value,
index
}
}
export </span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> DemoHoc ({ Com }: any) {
const [ u, setU ] </span>= React.useState(1<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>
<Com useReducer={(reducer: Reducer, initalState?: State) =><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> demoReducer(reducer, initalState, () =><span style="color: rgba(0, 0, 0, 1)"> {
index </span>= 0<span style="color: rgba(0, 0, 0, 1)">;
setU(u </span>+ 1<span style="color: rgba(0, 0, 0, 1)">);
})
}} </span>/>
</div>
<span style="color: rgba(0, 0, 0, 1)"> )
}</span></pre>
</div>
<p> </p>
<p>使用文件:</p>
<p class="sync-line" data-line="322"> </p>
<div class="cnblogs_code">
<pre>import * as React from 'react'<span style="color: rgba(0, 0, 0, 1)">;
import { DemoHoc, UseReducer } from </span>'./useReducer/useReducerDemo'<span style="color: rgba(0, 0, 0, 1)">
import { Button } from </span>'antd'<span style="color: rgba(0, 0, 0, 1)">;
export </span><span style="color: rgba(0, 0, 255, 1)">default</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> HookDemo () {
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (
</span><DemoHoc Com={DemoComponent} />
<span style="color: rgba(0, 0, 0, 1)"> )
}
const initialState </span>= {count: 0<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)"> reducer(state: any, action: any) {
</span><span style="color: rgba(0, 0, 255, 1)">switch</span><span style="color: rgba(0, 0, 0, 1)"> (action.type) {
</span><span style="color: rgba(0, 0, 255, 1)">case</span> 'increment'<span style="color: rgba(0, 0, 0, 1)">:
</span><span style="color: rgba(0, 0, 255, 1)">return</span> {count: state.count + 1<span style="color: rgba(0, 0, 0, 1)">};
</span><span style="color: rgba(0, 0, 255, 1)">case</span> 'decrement'<span style="color: rgba(0, 0, 0, 1)">:
</span><span style="color: rgba(0, 0, 255, 1)">return</span> {count: state.count - 1<span style="color: rgba(0, 0, 0, 1)">};
</span><span style="color: rgba(0, 0, 255, 1)">default</span><span style="color: rgba(0, 0, 0, 1)">:
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Error();
}
}
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> DemoComponent({ useReducer }: {
useReducer: UseReducer
}) {
const [ state, dispatch ] </span>=<span style="color: rgba(0, 0, 0, 1)"> useReducer(reducer, initialState);
const [ state2, dispatch2 ] </span>=<span style="color: rgba(0, 0, 0, 1)"> useReducer(reducer, {...initialState});
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (
</span><div><span style="color: rgba(0, 0, 0, 1)">
Count: {state.count}
</span><Button onClick={() => dispatch({type: 'decrement'})}>-</Button>
<Button onClick={() => dispatch({type: 'increment'})}>+</Button>
<div></div>
<span style="color: rgba(0, 0, 0, 1)"> Count2: {state2.count}
</span><Button onClick={() => dispatch2({type: 'decrement'})}>-</Button>
<Button onClick={() => dispatch2({type: 'increment'})}>+</Button>
</div>
<span style="color: rgba(0, 0, 0, 1)"> )
}</span></pre>
</div>
<p> </p>
<p>原理:<br>我们先看实现文件的这个函数(不了解ts的同学,可以忽略ts的理解):</p>
<p class="sync-line" data-line="369"> </p>
<div class="cnblogs_code">
<pre>const memo: Queue<State>[] =<span style="color: rgba(0, 0, 0, 1)"> [];
let index </span>= 0<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">function</span> demoReducer (reducer: Reducer, initalState?: State, update?: () => <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)">) : any[] {
let has </span>= !!<span style="color: rgba(0, 0, 0, 1)">memo;
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">memo) {
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (index === 0<span style="color: rgba(0, 0, 0, 1)">) {
memo[</span>0] = GeQueue<State><span style="color: rgba(0, 0, 0, 1)">(initalState, index);
memo[</span>0].root =memo;
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
memo </span>= GeQueue<State><span style="color: rgba(0, 0, 0, 1)">(initalState, index);
memo.root </span>=memo;
memo.prev </span>= memo;
memo.next =<span style="color: rgba(0, 0, 0, 1)"> memo;
}
index </span>= index + 1<span style="color: rgba(0, 0, 0, 1)">;
}
let state;
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (has) {
state </span>=<span style="color: rgba(0, 0, 0, 1)"> memo.value;
index </span>= index + 1<span style="color: rgba(0, 0, 0, 1)">;
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
state </span>= memo.value;
}
let bindex </span>=<span style="color: rgba(0, 0, 0, 1)"> index;
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> [
state,
(action: string) </span>=><span style="color: rgba(0, 0, 0, 1)"> {
memo.value = reducer(memo.value, action)
update();
}
]
}</span></pre>
</div>
<p> </p>
<ul>
<li>最开始,我们用了一个memo对象(它是一个队列)这里简单的定义成数组。 然后又又一个index,记录数字关系</li>
<li>然后重点来了</li>
</ul>
<p class="sync-line" data-line="406"> </p>
<div class="cnblogs_code">
<pre>let has = !!<span style="color: rgba(0, 0, 0, 1)">memo;
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">memo) {
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (index === 0<span style="color: rgba(0, 0, 0, 1)">) {
memo[</span>0] = GeQueue<State><span style="color: rgba(0, 0, 0, 1)">(initalState, index);
memo[</span>0].root =memo;
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
memo </span>= GeQueue<State><span style="color: rgba(0, 0, 0, 1)">(initalState, index);
memo.root </span>=memo;
memo.prev </span>= memo;
memo.next =<span style="color: rgba(0, 0, 0, 1)"> memo;
}
index </span>= index + 1<span style="color: rgba(0, 0, 0, 1)">;
}
let state;
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (has) {
state </span>=<span style="color: rgba(0, 0, 0, 1)"> memo.value;
index </span>= index + 1<span style="color: rgba(0, 0, 0, 1)">;
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
state </span>= memo.value;
}
let bindex </span>= index;</pre>
</div>
<p> </p>
<p>我们调用useReducer的时候,从memo中尝试获取index的值,若存在的话,将state赋值为当前memo里的值并返回</p>
<ul>
<li>最后我们提供了一个触发更新的函数</li>
</ul>
<p>然后-我们再看看使用的代码:</p>
<p class="sync-line" data-line="434"> </p>
<div class="cnblogs_code">
<pre>const initialState = {count: 0<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)"> reducer(state: any, action: any) {
</span><span style="color: rgba(0, 0, 255, 1)">switch</span><span style="color: rgba(0, 0, 0, 1)"> (action.type) {
</span><span style="color: rgba(0, 0, 255, 1)">case</span> 'increment'<span style="color: rgba(0, 0, 0, 1)">:
</span><span style="color: rgba(0, 0, 255, 1)">return</span> {count: state.count + 1<span style="color: rgba(0, 0, 0, 1)">};
</span><span style="color: rgba(0, 0, 255, 1)">case</span> 'decrement'<span style="color: rgba(0, 0, 0, 1)">:
</span><span style="color: rgba(0, 0, 255, 1)">return</span> {count: state.count - 1<span style="color: rgba(0, 0, 0, 1)">};
</span><span style="color: rgba(0, 0, 255, 1)">default</span><span style="color: rgba(0, 0, 0, 1)">:
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Error();
}
}
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> DemoComponent({ useReducer }: {
useReducer: UseReducer
}) {
const [ state, dispatch ] </span>=<span style="color: rgba(0, 0, 0, 1)"> useReducer(reducer, initialState);
const [ state2, dispatch2 ] </span>=<span style="color: rgba(0, 0, 0, 1)"> useReducer(reducer, {...initialState});
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (
</span><div><span style="color: rgba(0, 0, 0, 1)">
Count: {state.count}
</span><Button onClick={() => dispatch({type: 'decrement'})}>-</Button>
<Button onClick={() => dispatch({type: 'increment'})}>+</Button>
<div></div>
<span style="color: rgba(0, 0, 0, 1)"> Count2: {state2.count}
</span><Button onClick={() => dispatch2({type: 'decrement'})}>-</Button>
<Button onClick={() => dispatch2({type: 'increment'})}>+</Button>
</div>
<span style="color: rgba(0, 0, 0, 1)"> )
}</span></pre>
</div>
<p> </p>
<ul>
<li>useReducer时经过memo的存储,我们在队列结构里存下了值,当dispatch的时候,memo中的变量将会改变。</li>
</ul>
<p>所以各位看出来了吗?</p>
<h3>这就是hooks隐藏的逻辑所在!</h3>
<p>重点来了~<br><strong>hooks的本质是什么?</strong></p>
<p class="sync-line" data-line="478"> 注:我的实现是为了理解它,与官方源码存在出入哈,理解原理就好~</p>
<h2 id="hooks%E6%9C%AC%E8%B4%A8%E7%9C%8B%E5%9D%91%E4%B8%8E%E8%A7%84%E8%8C%83" class="mume-header">Hooks本质看坑与规范</h2>
<p>hooks的本质是-闭包。<br>它在外部作用域存储了值。<br>当setState发生时,整个函数(相当于render)都被触发调用,那么所有的变量就会重新赋值就像是下面的关键字:</p>
<ul>
<li>const</li>
<li>let</li>
<li>function<br>好多同学会觉得,奇怪了,为啥这个函数被重新调用,不会重新赋值呢?<br>关键就是闭包!<br>事实上hooks的每个setState都会导致function变成一个片段。在这之前的变量并不是之后的变量。<br>而我们在onclick等事件中引用的函数,有可能会存储旧的变量引用!这就会导致一些大问题!!!</li>
<li>例如内存泄漏</li>
<li>例如值的引用无效<br>那怎么解决?<br>react其实提供了解决办法,就是useMemo useCallback等等。你可以再深入的去理解它。</li>
</ul>
<p><strong>Hooks使用大忌</strong></p>
<p>1、 外部顶层变量问题,不要把全局变量放在函数外部,特别是你在开发公共组件的时候,你可以用useRef<br>2、依赖项不正确问题,依赖项不正确会导致闭包问题。<br>3、组件拆分太粗问题,函数不建议太长,500行以内最佳<br>4、盲目使用usexxx,要深刻理解才能更好的使用hooks</p>
<p class="sync-line" data-line="502"> </p>
<h2 id="%E6%9C%80%E5%90%8E" class="mume-header">最后</h2>
<p>高效编码;健康生活;</p>
<p>招人啦招人啦,SHEIN前端岗后端岗等你来投,可以私信博主,也可以扫码查看。期待与你做同事!</p>
<p><img src="https://img2020.cnblogs.com/blog/893115/202103/893115-20210304185950925-1183937448.png" alt="" width="494" height="879" loading="lazy"></p>
<p> </p>
</div>
<div id="MySignature" role="contentinfo">
========================================================
转载请注明出处。<br><br>
来源:https://www.cnblogs.com/ztfjs/p/hooks.html
頁:
[1]