国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

重拾React: Context

曹金海 / 2939人閱讀

前言

  首先歡迎大家關(guān)注我的Github博客,也算是對(duì)我的一點(diǎn)鼓勵(lì),畢竟寫東西沒法獲得變現(xiàn),能堅(jiān)持下去也是靠的是自己的熱情和大家的鼓勵(lì),希望大家多多關(guān)注呀!好久已經(jīng)沒寫React,發(fā)現(xiàn)連Context都發(fā)生了變化,忽然有一種村里剛通上的網(wǎng)的感覺,可能文章所提及的知識(shí)點(diǎn)已經(jīng)算是過時(shí)了,僅僅算作是自己的學(xué)習(xí)體驗(yàn)吧,

Context

  對(duì)于React開發(fā)者而言,Context應(yīng)該是一個(gè)不陌生的概念,但是在16.3之前,React官方一直不推薦使用,并聲稱該特性屬于實(shí)驗(yàn)性質(zhì)的API,可能會(huì)從之后的版本中移除。但是在實(shí)踐中非常多的第三方庫都基于該特性,例如:react-redux、mobx-react。

  如上面的組件樹中,A組件與B組件之間隔著非常多的組件,假如A組件希望傳遞給B組件一個(gè)屬性,那么不得不使用props將屬性從A組件歷經(jīng)一系列中間組件最終跋山涉水傳遞給B組件。這樣代碼不僅非常的麻煩,更重要的是中間的組件可能壓根就用不上這個(gè)屬性,卻要承擔(dān)一個(gè)傳遞的職責(zé),這是我們不希望看見的。Context出現(xiàn)的目的就是為了解決這種場(chǎng)景,使得我們可以直接將屬性從A組件傳遞給B組件。

Legacy Context

  這里所說的老版本Context指的是React16.3之前的版本所提供的Context屬性,在我看來,這種Context是以一種協(xié)商聲明的方式使用的。作為屬性提供者(Provider)需要顯式聲明哪些屬性可以被跨層級(jí)訪問并且需要聲明這些屬性的類型。而作為屬性的使用者(Consumer)也需要顯式聲明要這些屬性的類型。官方文檔中給出了下面的例子:

import React, {Component} from "react";
import PropTypes from "prop-types";

class Button extends React.Component {

    static contextTypes = {
        color: PropTypes.string
    };

    render() {
        return (
            
        );
    }
}

class Message extends React.Component {
    render() {
        return (
            
{this.props.text}
); } } class MessageList extends React.Component { static childContextTypes = { color: PropTypes.string }; getChildContext() { return {color: "red"}; } render() { const children = this.props.messages.map((message) => ); return
{children}
; } }

  我們可以看到MessageList通過函數(shù)getChildContext顯式聲明提供color屬性,并且通過靜態(tài)屬性childContextTypes聲明了該屬性的類型。而Button通過靜態(tài)屬性contextTypes聲明了要使用屬性的類型,二者通過協(xié)商的方式約定了跨層級(jí)傳遞屬性的信息。Context確實(shí)非常方便的解決了跨層級(jí)傳遞屬性的情況,但是為什么官方卻不推薦使用呢?

  首先Context的使用是與React可復(fù)用組件的邏輯背道而馳的,在React的思維中,所有組件應(yīng)該具有復(fù)用的特性,但是正是因?yàn)镃ontext的引入,組件復(fù)用的使用變得嚴(yán)格起來。就以上面的代碼為例,如果想要復(fù)用Button組件,必須在上層組件中含有一個(gè)可以提供String類型的colorContext,所以復(fù)用要求變得嚴(yán)格起來。并且更重要的是,當(dāng)你嘗試修改Context的值時(shí),可能會(huì)觸發(fā)不確定的狀態(tài)。我們舉一個(gè)例子,我們將上面的MessageList稍作改造,使得Context內(nèi)容可以動(dòng)態(tài)改變:

class MessageList extends React.Component {

    state = {
        color: "red"
    };

    static childContextTypes = {
        color: PropTypes.string
    };

    getChildContext() {
        return {color: this.state.color};
    }

    render() {
        const children = this.props.messages.map((message) =>
            
        );
        return (
            
{children}
); } _changeColor = () => { const colors = ["red", "green", "blue"]; const index = (colors.indexOf(this.state.color) + 1) % 3; this.setState({ color: colors[index] }); } }

  上面的例子中我們MessageList組件Context提供的color屬性改成了state的屬性,當(dāng)每次使用setState刷新color的時(shí)候,子組件也會(huì)被刷新,因此對(duì)應(yīng)按鈕的顏色也會(huì)發(fā)生改變,一切看起來是非常的完美。但是一旦組件間的組件存在生命周期函數(shù)ShouldComponentUpdate那么一切就變得詭異起來。我們知道PureComponent實(shí)質(zhì)就是利用ShouldComponentUpdate避免不必要的刷新的,因此我們可以對(duì)之前的例子做一個(gè)小小的改造:

class Message extends React.PureComponent {
    render() {
        return (
            
{this.props.text}
); } }

  你會(huì)發(fā)現(xiàn)即使你在MessageList中改變了Context的值,也無法導(dǎo)致子組件中按鈕的顏色刷新。這是因?yàn)?b>Message組件繼承自PureComponent,在沒有接受到新的props改變或者state變化時(shí)生命周期函數(shù)shouldComponentUpdate返回的是false,因此Message及其子組件并沒有刷新,導(dǎo)致Button組件沒有刷新到最新的顏色。

  如果你的Context值是不會(huì)改變的,或者只是在組件初始化的時(shí)候才會(huì)使用一次,那么一切問題都不會(huì)存在。但是如果需要改變Context的情況下,如何安全使用呢? Michel Weststrate在[How to safely use React context
](https://medium.com/@mweststra...。作者認(rèn)為我們不應(yīng)該直接在getChildContext中直接返回state屬性,而是應(yīng)該像依賴注入(DI)一樣使用conext。

class Theme {
    constructor(color) {
        this.color = color
        this.subscriptions = []
    }

    setColor(color) {
        this.color = color
        this.subscriptions.forEach(f => f())
    }

    subscribe(f) {
        this.subscriptions.push(f)
    }
}

class Button extends React.Component {
    static contextTypes = {
        theme: PropTypes.Object
    };

    componentDidMount() {
        this.context.theme.subscribe(() => this.forceUpdate());
    }

    render() {
        return (
            
        );
    }
}

class MessageList extends React.Component {

    constructor(props){
        super(props);
        this.theme = new Theme("red");
    }

    static childContextTypes = {
        theme: PropTypes.Object
    };

    getChildContext() {
        return {
            theme: this.theme
        };
    }

    render() {
        const children = this.props.messages.map((message) =>
            
        );
        return (
            
{children}
); } _changeColor = () => { const colors = ["red", "green", "blue"]; const index = (colors.indexOf(this.theme.color) + 1) % 3; this.theme.setColor(colors[index]); } }

  在上面的例子中我們創(chuàng)造了一個(gè)Theme類用來管理樣式,然后通過ContextTheme的實(shí)例向下傳遞,在Button中獲取到該實(shí)例并且訂閱樣式變化,在樣式變化時(shí)調(diào)用forceUpdate強(qiáng)制刷新達(dá)到刷新界面的目的。當(dāng)然上面的例子只是一個(gè)雛形,具體使用時(shí)還需要考慮到其他的方面內(nèi)容,例如在組件銷毀時(shí)需要取消監(jiān)聽等方面。

  回顧一下之前版本的Context,配置起來還是比較麻煩的,尤其還需要在對(duì)應(yīng)的兩個(gè)組件中分別使用childContextTypescontextTypes的聲明Context屬性的類型。而且其實(shí)這兩個(gè)類型聲明并不能很好的約束context。舉一個(gè)例子,假設(shè)分別有三個(gè)組件: GrandFather、Father、Son,渲染順序分別是:

GrandFather -> Father -> Son

  那么假設(shè)說組件GrandFather提供的context是類型為number鍵為value的值1,而Father提供也是類型為number的鍵為value的值2,組件Son聲明獲得的是類型為number的鍵為value的context,我們肯定知道組件Son中this.context.value值為2,因?yàn)閏ontext在遇到同名Key值時(shí)肯定取的是最靠近的父組件。

  同樣地我們假設(shè)件GrandFather提供的context是類型為string鍵為value的值"1",而Father提供是類型為number的鍵為value的值2,組件Son聲明獲得的是類型為string的鍵為value的context,那么組件Son會(huì)取到GrandFather的context值嗎?事實(shí)上并不會(huì),仍然取到的值是2,只不過在開發(fā)過程環(huán)境下會(huì)輸出:

Invalid context value of type number supplied to Son, expected string

  因此我們能得出靜態(tài)屬性childContextTypescontextTypes只能提供開發(fā)的輔助性作用,對(duì)實(shí)際的context取值并不能起到約束性的作用,即使這樣我們也不得不重復(fù)體力勞動(dòng),一遍遍的聲明childContextTypescontextTypes屬性。

New Context

  新的Context發(fā)布于React 16.3版本,相比于之前組件內(nèi)部協(xié)商聲明的方式,新版本下的Context大不相同,采用了聲明式的寫法,通過render props的方式獲取Context,不會(huì)受到生命周期shouldComponentUpdate的影響。上面的例子用新的Context改寫為:

import React, {Component} from "react";

const ThemeContext = React.createContext({ theme: "red"});

class Button extends React.Component {
    render(){
        return(
            
                {({color}) => {
                    return (
                        
                    );
                }}
            
        );
    }
}

class Message extends React.PureComponent {
    render() {
        return (
            
{this.props.text}
); } } class MessageList extends React.Component { state = { theme: { color: "red" } }; render() { return (
{this.props.messages.map((message) => )}
) } _changeColor = () => { const colors = ["red", "green", "blue"]; const index = (colors.indexOf(this.state.theme.color) + 1) % 3; this.setState({ theme: { color: colors[index] } }); } }

  我們可以看到新的Context使用React.createContext的方式創(chuàng)建了一個(gè)Context實(shí)例,然后通過Provider的方式提供Context值,而通過Consumer配合render props的方式獲取到Context值,即使中間組件中存在shouldComponentUpdate返回false,也不會(huì)導(dǎo)致Context無法刷新的問題,解決了之前存在的問題。我們看到在調(diào)用React.createContext創(chuàng)建Context實(shí)例的時(shí)候,我們傳入了一個(gè)默認(rèn)的Context值,該值僅會(huì)在Consumer在組件樹中無法找到匹配的Provider才會(huì)使用,因此即使你給Providervalue傳入undefined值時(shí),Consumer也不會(huì)使用默認(rèn)值。

  新版的Context API相比于之前的Context API更符合React的思想,并且能解決componentShouldUpdate的帶來的問題。與此同時(shí)你的項(xiàng)目需要增加專門的文件來創(chuàng)建Context。在 React v17 中,可能就會(huì)刪除對(duì)老版 Context API 的支持,所以還是需要盡快升級(jí)。最后講了這么多,但是在項(xiàng)目中還是要盡量避免Context的濫用,否則會(huì)造成組件間依賴過于復(fù)雜。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/101146.html

相關(guān)文章

  • 重拾React: React 16.0

    摘要:然而之前的相當(dāng)于從最頂層的組件開始,自頂向下遞歸調(diào)用,不會(huì)被中斷,這樣就會(huì)持續(xù)占用瀏覽器主線程。眾所周知,是單線程運(yùn)行,長(zhǎng)時(shí)間占用主線程會(huì)阻塞其他類似于樣式計(jì)算布局繪制等運(yùn)算,從而出現(xiàn)掉幀的情況。 前言   首先歡迎大家關(guān)注我的Github博客,也算是對(duì)我的一點(diǎn)鼓勵(lì),畢竟寫東西沒法獲得變現(xiàn),能堅(jiān)持下去也是靠的是自己的熱情和大家的鼓勵(lì),希望大家多多關(guān)注呀!從今年年初離開React開發(fā)崗,...

    henry14 評(píng)論0 收藏0
  • 重拾JSX

    摘要:語法糖是一種的語法拓展,可以使用它來進(jìn)行的展示我們一般會(huì)在組件的方法里使用進(jìn)行布局和事件綁定的核心機(jī)制之一就是可以創(chuàng)建虛擬的元素,利用虛擬來減少對(duì)實(shí)際的操作從而提升性能,正是為了虛擬而存在的語法糖我們?cè)谄綍r(shí)的組件編寫中,通常都這么寫然而代碼 React.createElement語法糖 JSX是一種JavaScript的語法拓展,可以使用它來進(jìn)行UI的展示: const element...

    adam1q84 評(píng)論0 收藏0
  • 重拾-MyBatis-配置文件解析

    摘要:前言我們知道在使用時(shí),我們需要通過去創(chuàng)建實(shí)例,譬如為的配置文件那么我們看下方法的具體實(shí)現(xiàn)創(chuàng)建實(shí)例并執(zhí)行解析主要通過執(zhí)行對(duì)配置文件的解析,具體實(shí)現(xiàn)如下文配置文件解析解析標(biāo)簽解析標(biāo)簽解析別名標(biāo)簽解析插件標(biāo)簽解析標(biāo)簽解析標(biāo)簽解析標(biāo)簽從的方法實(shí)現(xiàn)我 前言 我們知道在使用 Mybatis 時(shí),我們需要通過 SqlSessionFactoryBuild 去創(chuàng)建 SqlSessionFactory ...

    王晗 評(píng)論0 收藏0
  • 重拾-Spring-IOC

    摘要:為何重拾使用了多年,但是對(duì)其底層的一些實(shí)現(xiàn)還是一知半解,一些概念比較模糊故決定重新拾起,加深對(duì)的認(rèn)識(shí)。小結(jié)是在完成創(chuàng)建后對(duì)其進(jìn)行后置處理的接口是在完成實(shí)例化對(duì)其進(jìn)行的后置處理接口是框架底層的核心接口,其提供了創(chuàng)建,獲取等核心功能。 為何重拾 使用了 Spring 多年,但是對(duì)其底層的一些實(shí)現(xiàn)還是一知半解,一些概念比較模糊;故決定重新拾起,加深對(duì) Spring 的認(rèn)識(shí)。 重拾計(jì)劃 spr...

    GraphQuery 評(píng)論0 收藏0
  • 重拾golang - go目錄結(jié)構(gòu)說明

    摘要:目錄結(jié)構(gòu)說明集多編程范式之大成者,使開發(fā)者能夠快速的開發(fā)測(cè)試部署程序,支持全平臺(tái)靜態(tài)編譯。上目錄位置主要目錄包含如下圖,分別進(jìn)行說明文件夾存放檢查器的輔助文件。工作區(qū)有個(gè)子目錄目錄目錄和目錄。目錄用于以代碼包的形式組織并保存源碼文件。 go 目錄結(jié)構(gòu)說明 ??golang集多編程范式之大成者,使開發(fā)者能夠快速的開發(fā)、測(cè)試、部署程序,支持全平臺(tái)靜態(tài)編譯。go具有優(yōu)秀的依賴管理,高效的運(yùn)行...

    zhisheng 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<