证券研究院 發表於 2023-1-30 17:37:00

react useContext

<h2>一、什么是useContext</h2>
<p data-first-child="" data-pid="cM75TXTl">在 React class 式中父组件向子组件传递参数可以通过 props ,context。但是在函数式组件中需要向多层组件传递数据时,此时就可以使用 useContext/</p>
<h2>二、useContext的作用</h2>
<div>
<h3>1.useContext可以帮助我们跨越组件层级直接传递变量,实现数据共享。</h3>
<blockquote>
<ul>
<li>这里要注意的是,很多同学觉得可以使用useContext结合useReducer来替代redux,其实两者的作用是不同的。</li>
<li>useContext:解决组件间传值的问题。</li>
<li>redux:统一管理应用状态。</li>
<li>所以,我们可以使用useContext结合useReducer来模拟一个小型redux场景,而无法替代redux</li>
</ul>
</blockquote>
<h3>2.Context的作用就是对它所包含的组件树提供全局共享数据的一种技术。</h3>
<h2>三、代码示例</h2>
<div class="cnblogs_code">
<pre>import React, { useState } from "react"<span style="color: rgba(0, 0, 0, 1)">;

let Theme </span>= React.createContext("red"<span style="color: rgba(0, 0, 0, 1)">);

const Inner </span>= () =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
let color </span>=<span style="color: rgba(0, 0, 0, 1)"> React.useContext(Theme);
</span><span style="color: rgba(0, 0, 255, 1)">return</span> &lt;div&gt;&lt;span style={{color: color}}&gt;文字&lt;/span&gt;&lt;/div&gt;<span style="color: rgba(0, 0, 0, 1)">
}

const Con </span>= () =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> &lt;Inner /&gt;
<span style="color: rgba(0, 0, 0, 1)">}

const Side </span>= () =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
console.log(</span>"side"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">return</span> &lt;&gt;&lt;span&gt;side&lt;/span&gt;&lt;/&gt;<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)"> App() {
const </span>= useState("red"<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>&lt;div className="App"&gt;
      &lt;button onClick={() =&gt; setColor("red")}&gt;红色&lt;/button&gt;
      &lt;button onClick={() =&gt; setColor("green")}&gt;绿色&lt;/button&gt;
      &lt;Theme.Provider value={color}&gt;
      &lt;Con /&gt;
      &lt;Side /&gt;
      &lt;/Theme.Provider&gt;
    &lt;/div&gt;
<span style="color: rgba(0, 0, 0, 1)">);
}</span></pre>
</div>
<p data-pid="uhP0-OCW">在上面的例子中,我通过在顶层创建 Provider 组件,深层次的子组件通过 useContext 取得 值,这样使得在父组件修改 context 的值之后,子组件也能取得相对应的值,并重新渲染。</p>
<p data-pid="b7D2j7sv">需要注意的是,useContext 函数接收的参数对象是 context 自身。</p>
<p data-pid="IYKmz7xa">存在于Provider 组件下的子组件在context 的值发生变化后,都会重新渲染,这样可能会引发一些性能问题,我们可以通过 memo 去避免一些不必要的重渲染。</p>
<div>
<div class="cnblogs_code">
<pre>const Side = memo(() =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
console.log(</span>"side"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">return</span> &lt;&gt;&lt;span&gt;side&lt;/span&gt;&lt;/&gt;<span style="color: rgba(0, 0, 0, 1)">
})</span></pre>
</div>
<p data-pid="_yx_ifhR">Context 是通过新旧值检测来确定变化,使用了与<code>Object.is</code>相同的算法。</p>
<p data-pid="DRfx-31o">如果传给Context 是个字面对象的话,有可能使得每次值的检测都会使得子组件重新渲染。</p>
</div>
<div class="highlight">
<div class="cnblogs_code">
<pre>import React, { useState, memo } from "react"<span style="color: rgba(0, 0, 0, 1)">;

let Theme </span>= React.createContext({color:"red"<span style="color: rgba(0, 0, 0, 1)">});

const Inner </span>= memo(() =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
let theme </span>=<span style="color: rgba(0, 0, 0, 1)"> React.useContext(Theme);
console.log(</span>"Inner"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">return</span> &lt;div&gt;&lt;span style={{color: theme.color}}&gt;文字&lt;/span&gt;&lt;/div&gt;<span style="color: rgba(0, 0, 0, 1)">
})

const Con </span>= () =&gt;<span style="color: rgba(0, 0, 0, 1)"> {

</span><span style="color: rgba(0, 0, 255, 1)">return</span> &lt;Inner /&gt;
<span style="color: rgba(0, 0, 0, 1)">}

const Side </span>= memo(() =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
console.log(</span>"side"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">return</span> &lt;&gt;&lt;span&gt;side&lt;/span&gt;&lt;/&gt;<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)"> App() {
const </span>= useState("red"<span style="color: rgba(0, 0, 0, 1)">)
const </span>= 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>&lt;div className="App"&gt;
      &lt;div&gt;<span style="color: rgba(0, 0, 0, 1)">
      {count}
      </span>&lt;button onClick={() =&gt; setCount((v) =&gt; v + 1 )}&gt;count&lt;/button&gt;
      &lt;/div&gt;
      &lt;button onClick={() =&gt; setColor("red")}&gt;红色&lt;/button&gt;
      &lt;button onClick={() =&gt; setColor("green")}&gt;绿色&lt;/button&gt;
      &lt;Theme.Provider value={{color}}&gt;
      &lt;Con /&gt;
      &lt;Side /&gt;
      &lt;/Theme.Provider&gt;
    &lt;/div&gt;
<span style="color: rgba(0, 0, 0, 1)">);
}</span></pre>
</div>
<p>上述的代码中,因为父组件 App 重新渲染时提供给Conext 的都是一个新的字面量对象,导致Inner 组件会在父组件的每次重渲染中去跟着重新渲染,这实际上是没有必要的。</p>
&nbsp;
<div class="cnblogs_code">
<pre>import React, { useState, memo } from "react"<span style="color: rgba(0, 0, 0, 1)">;

let Theme </span>= React.createContext({color:"red"<span style="color: rgba(0, 0, 0, 1)">});

const Inner </span>= memo(() =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
let theme </span>=<span style="color: rgba(0, 0, 0, 1)"> React.useContext(Theme);
console.log(</span>"Inner"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">return</span> &lt;div&gt;&lt;span style={{color: theme.color}}&gt;文字&lt;/span&gt;&lt;/div&gt;<span style="color: rgba(0, 0, 0, 1)">
})

const Con </span>= () =&gt;<span style="color: rgba(0, 0, 0, 1)"> {

</span><span style="color: rgba(0, 0, 255, 1)">return</span> &lt;Inner /&gt;
<span style="color: rgba(0, 0, 0, 1)">}

const Side </span>= memo(() =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> &lt;&gt;&lt;span&gt;side&lt;/span&gt;&lt;/&gt;<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)"> App() {
const </span>= useState({color: "red"<span style="color: rgba(0, 0, 0, 1)">})
const </span>= 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>&lt;div className="App"&gt;
      &lt;div&gt;<span style="color: rgba(0, 0, 0, 1)">
      {count}
      </span>&lt;button onClick={() =&gt; setCount((v) =&gt; v + 1 )}&gt;count&lt;/button&gt;
      &lt;/div&gt;
      &lt;button onClick={() =&gt; setTheme({color: "red"})}&gt;红色&lt;/button&gt;
      &lt;button onClick={() =&gt; setTheme({color: "green"})}&gt;绿色&lt;/button&gt;
      &lt;Theme.Provider value={theme}&gt;
      &lt;Con /&gt;
      &lt;Side /&gt;
      &lt;/Theme.Provider&gt;
    &lt;/div&gt;
<span style="color: rgba(0, 0, 0, 1)">);
}</span></pre>
</div>
<div class="Post-RichTextContainer">
<div class="css-1yuhvjn">
<div class="css-376mun">
<div class="RichText ztext Post-RichText css-1g0fqss">
<p data-pid="jdIv2Q-6">通过上面的修改后,使得 Inner 避免了不必要的渲染。</p>
</div>
</div>
</div>
</div>
</div>
</div><br><br>
来源:https://www.cnblogs.com/momo798/p/17076798.html
頁: [1]
查看完整版本: react useContext