疲惫不堪 發表於 2019-8-2 10:54:00

React Hooks: useCallback理解

<h2>useCallback把匿名回调“存”起来</h2>
<p>避免在component render时候声明匿名方法,因为这些匿名方法会被反复重新声明而无法被多次利用,然后容易造成component反复不必要的渲染。</p>
<p>&nbsp;在Class component当中我们通常将回调函数声明为类成员:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">class MyComponent extends React.Component {
    constructor(props) {
      super(props);
      </span><span style="color: rgba(0, 0, 255, 1)">this</span>.clickCallback = <span style="color: rgba(0, 0, 255, 1)">this</span>.clickCallback.bind(<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">);
    }
    clickCallback() {
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ...</span>
<span style="color: rgba(0, 0, 0, 1)">    }
    render() {
      </span><span style="color: rgba(0, 0, 255, 1)">return</span> &lt;button onClick={<span style="color: rgba(0, 0, 255, 1)">this</span>.clickCallback}&gt;Click Me!&lt;/button&gt;;
<span style="color: rgba(0, 0, 0, 1)">    }
}</span></pre>
</div>
<p>使用useCallback hook就可以避免bind操作:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> MyComponent(props) {
    const clickCallback </span>= React.useCallback(() =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ...</span>
<span style="color: rgba(0, 0, 0, 1)">    }, []);
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> &lt;button onClick={clickCallback}&gt;Click Me!&lt;/button&gt;;
}</pre>
</div>
<h2>useCallback缓存函数</h2>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">const fnA = useCallback(fnB, )
</pre>
</div>
<p>  上面的useCallback会将我们传递给它的函数fnB返回,并且将这个结果缓存;当依赖a变更时,会返回新的函数。既然返回的是函数,我们无法很好的判断返回的函数是否变更,所以我们可以借助ES6新增的数据类型Set来判断,具体如下:</p>
<div class="cnblogs_code">
<pre>import React, { useState, useCallback } from 'react'<span style="color: rgba(0, 0, 0, 1)">;

const set </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Set();

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)"> Callback() {
    const </span>= useState(1<span style="color: rgba(0, 0, 0, 1)">);
    const </span>= useState(''<span style="color: rgba(0, 0, 0, 1)">);

    const callback </span>= useCallback(() =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
      console.log(count);
    }, );
    set.add(callback);


    </span><span style="color: rgba(0, 0, 255, 1)">return</span> &lt;div&gt;
      &lt;h4&gt;{count}&lt;/h4&gt;
      &lt;h4&gt;{set.size}&lt;/h4&gt;
      &lt;div&gt;
            &lt;button onClick={() =&gt; setCount(count + 1)}&gt;+&lt;/button&gt;
            &lt;input value={val} onChange={event =&gt; setVal(event.target.value)}/&gt;
      &lt;/div&gt;
    &lt;/div&gt;;
}</pre>
</div>
<p>我们可以看到,每次修改count,set.size就会+1,这说明useCallback依赖变量count,count变更时会返回新的函数;而val变更时,set.size不会变,说明返回的是缓存的旧版本函数。</p>
<h2>使用场景:</h2>
<p>有一个父组件,其中包含子组件,子组件接收一个函数作为props;通常而言,如果父组件更新了,子组件也会执行更新;但是大多数场景下,更新是没有必要的,我们可以借助useCallback来返回函数,然后把这个函数作为props传递给子组件;这样,子组件就能避免不必要的更新。</p>
<div class="cnblogs_code">
<pre>import React, { useState, useCallback, 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)"> Parent() {
    const </span>= useState(1<span style="color: rgba(0, 0, 0, 1)">);
    const </span>= useState(''<span style="color: rgba(0, 0, 0, 1)">);

    const callback </span>= useCallback(() =&gt;<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)"> count;
    }, );
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> &lt;div&gt;
      &lt;h4&gt;{count}&lt;/h4&gt;
      &lt;Child callback={callback}/&gt;
      &lt;div&gt;
            &lt;button onClick={() =&gt; setCount(count + 1)}&gt;+&lt;/button&gt;
            &lt;input value={val} onChange={event =&gt; setVal(event.target.value)}/&gt;
      &lt;/div&gt;
    &lt;/div&gt;;
<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)"> Child({ callback }) {
    const </span>= useState(() =&gt;<span style="color: rgba(0, 0, 0, 1)"> callback());
    useEffect(() </span>=&gt;<span style="color: rgba(0, 0, 0, 1)"> {
      setCount(callback());
    }, );
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> &lt;div&gt;<span style="color: rgba(0, 0, 0, 1)">
      {count}
    </span>&lt;/div&gt;
}</pre>
</div>
<p>不仅是上面的例子,所有依赖本地状态或props来创建函数,需要使用到缓存函数的地方,都是useCallback的应用场景。</p>
<p>useEffect、useMemo、useCallback都是自带闭包的。也就是说,每一次组件的渲染,其都会捕获当前组件函数上下文中的状态(state, props),所以每一次这三种hooks的执行,反映的也都是当前的状态,你无法使用它们来捕获上一次的状态。对于这种情况,我们应该使用ref来访问。</p><br><br>
来源:https://www.cnblogs.com/Nyan-Workflow-FC/p/11287276.html
頁: [1]
查看完整版本: React Hooks: useCallback理解