亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

react進(jìn)階系列:高階組件詳解(二)

JouyPub / 1379人閱讀

摘要:高階組件可以封裝公共邏輯,給當(dāng)前組件傳遞方法屬性,添加生命周期鉤子等。二是基礎(chǔ)組件的靜態(tài)方法也會(huì)因?yàn)楦唠A組件的包裹會(huì)丟失。如果在開發(fā)中確實(shí)遇到了必須使用它們,就一定要注意高階組件的這個(gè)問(wèn)題并認(rèn)真解決。

高階組件可以封裝公共邏輯,給當(dāng)前組件傳遞方法屬性,添加生命周期鉤子等。

案例:

一個(gè)項(xiàng)目中有的頁(yè)面需要判斷所處環(huán)境,如果在移動(dòng)端則正常顯示頁(yè)面,并向用戶提示當(dāng)前頁(yè)面所處的移動(dòng)端環(huán)境,如果不在移動(dòng)端則顯示提示讓其在移動(dòng)端打開。但是有的頁(yè)面又不需要這個(gè)判斷。

如果在每個(gè)頁(yè)面都寫一段判斷邏輯未免麻煩,因此可以借助高階組件來(lái)處理這部分邏輯。

先創(chuàng)建一個(gè)高階組件

// src/container/withEnvironment/index.jsx
import React from "react";

const envs = {
    weixin: "微信",
    qq: "QQ",
    baiduboxapp: "手機(jī)百度",
    weibo: "微博",
    other: "移動(dòng)端"
}

function withEnvironment(BasicComponent) {
    const ua = navigator.userAgent;
    const isMobile = "ontouchstart" in document;
    let env = "other";

    if (ua.match(/MicroMessenger/i)) {
        env = "weixin";
    }
    if (ua.match(/weibo/i)) {
        env = "weibo";
    }
    if (ua.match(/qq/i)) {
        env = "qq";
    }
    if (ua.match(/baiduboxapp/i)) {
        env = "baiduboxapp"
    }

    // 不同邏輯下返回不同的中間組件
    if (!isMobile) {
        return function () {
            return (
                
該頁(yè)面只能在移動(dòng)端查看,請(qǐng)掃描下方二維碼打開。
假設(shè)這里有張二維碼
) } } // 通過(guò)定義的中間組件將頁(yè)面所處環(huán)境通過(guò)props傳遞給基礎(chǔ)組件 const C = props => ( ) return C; } export default withEnvironment;

然后在基礎(chǔ)組件中使用

// src/pages/Demo01/index.jsx
import React from "react";
import withEnvironment from "../../container/withEnvironment";

function Demo01(props) {
    return (
        
你現(xiàn)在正在{props.envdesc}中訪問(wèn)該頁(yè)面
) } export default withEnvironment(Demo01);

最后將基礎(chǔ)組件渲染出來(lái)即可查看到效果。

// src/index.js
import React from "react";
import { render } from "react-dom";
import Demo01 from "./pages/Demo01";

const root = document.querySelector("#root");
render(, root);

在上面這個(gè)例子中,我們將環(huán)境判斷的邏輯放在了高階組件中處理,以后只要需要判斷環(huán)境的頁(yè)面只需要在基礎(chǔ)組件中這樣執(zhí)行即可。

export default withEnvironment(Demo01);

除此之外,我們?cè)趯?shí)際開發(fā)中還會(huì)遇到一個(gè)非常常見的需求,那就是在進(jìn)入一個(gè)頁(yè)面時(shí)需要判斷登錄狀態(tài),登錄狀態(tài)與非登錄狀態(tài)的不同顯示,登錄狀態(tài)之后角色的不同顯示都可以通過(guò)高階組件統(tǒng)一來(lái)處理這個(gè)邏輯,然后將登錄狀態(tài),角色信息等傳遞給基礎(chǔ)組件。

// 大概的處理邏輯
import React from "react";
import $ from "jquery";

// 假設(shè)已經(jīng)封裝了一個(gè)叫做getCookie的方法獲取cookie
import { getCookie } from "cookie";

function withRule(BasicComponent) {

    return class C extends React.Component {
        state = {
            islogin: false,
            rule: -1,
            loading: true,
            error: null
        }

        componentDidMount() {
            // 如果能直接在cookie中找到uid,說(shuō)明已經(jīng)登錄過(guò)并保存了相關(guān)信息
            if (getCookie("uid")) {
                this.setState({
                    islogin: true,
                    rule: getCookie("rule") || 0,
                    loading: false
                })
            } else {
                // 如果找不到uid,則嘗試自動(dòng)登錄,先從kookie中查找是否保存了登錄賬號(hào)與密碼
                const userinfo = getCookie("userinfo");
                if (userinfo) {
                    // 調(diào)用登錄接口
                    $.post("/api/login", {
                        username: userinfo.username,
                        password: userinfo.password
                    }).then(resp => {
                        this.setState({
                            islogin: true,
                            rule: resp.rule,
                            islogin: false
                        })
                    }).catch(err => this.setState({ error: err.message }))
                } else {
                    // 當(dāng)無(wú)法自動(dòng)登錄時(shí),你可以選擇在這里彈出登錄框,或者直接顯示未登錄頁(yè)面的樣式等都可以
                }
            }
        }

        render() {
            const { islogin, rule, loading, error } = this.state;

            if (error) {
                return (
                    
登錄接口請(qǐng)求失敗!錯(cuò)誤信息為:{error}
) } if (loading) { return (
頁(yè)面加載中, 請(qǐng)稍后...
) } return ( ) } } } export default withRule;

與第一個(gè)例子相比,這個(gè)例子更加接近實(shí)際應(yīng)用并且邏輯也更更加復(fù)雜。因此涉及到了異步數(shù)據(jù),因此最好的方式是在中間組件的componentDidMount中來(lái)處理邏輯。并在render中根據(jù)不同的狀態(tài)決定不同的渲染結(jié)果。

我們需要根據(jù)實(shí)際情況合理的使用react創(chuàng)建組件的兩種方式。這一點(diǎn)至關(guān)重要。上面兩個(gè)例子個(gè)人認(rèn)為還是比較典型的能代表大多數(shù)情況。

react-router中的高階組件

我們?cè)趯W(xué)習(xí)react的過(guò)程中,會(huì)逐漸的與高階組件打交道,react-router 中的 withRouter應(yīng)該算是會(huì)最早接觸到的高階組件。我們?cè)谑褂玫臅r(shí)候就知道,通過(guò)withRouter包裝的組件,我們可以在props中訪問(wèn)到location, router等對(duì)象,這正是withRouter通過(guò)高階組件的方式傳遞過(guò)來(lái)的。

import React, { Component } from "react";
import { withRouter } from "react-router";

class Home extends Component {
    componentDidMount() {
        const { router } = this.props;

        router.push("/");
    }
    render() {
        return (
            
...
) } } export default withRouter(Home);

我們可以來(lái)看看在react-router v4withRouter的源碼。

import React from "react";
import PropTypes from "prop-types";
import hoistStatics from "hoist-non-react-statics";
import Route from "./Route";

// 傳入基礎(chǔ)組件作為參數(shù)
const withRouter = (Component) => {

    // 創(chuàng)建中間組件
    const C = (props) => {
        const { wrappedComponentRef, ...remainingProps } = props;
        return (
             (
                // wrappedComponentRef 用來(lái)解決高階組件無(wú)法正確獲取到ref的問(wèn)題
                
            )}/>
        )
    }

    C.displayName = `withRouter(${Component.displayName || Component.name})`;
    C.WrappedComponent = Component;
    C.propTypes = {
        wrappedComponentRef: PropTypes.func
    }

    // hoistStatics類似于Object.assign,用于解決基礎(chǔ)組件因?yàn)楦唠A組件的包裹而丟失靜態(tài)方法的問(wèn)題
    return hoistStatics(C, Component);
}

export default withRouter;

如果對(duì)于高階組件的例子你已經(jīng)熟知,那么withRouter的源碼其實(shí)很容易理解。它做所的工作就僅僅只是把routeComponentProps傳入基礎(chǔ)組件而已。

另外還需要注意點(diǎn)是在該源碼中,解決了兩個(gè)因?yàn)楦唠A組件帶來(lái)的問(wèn)題,一個(gè)是經(jīng)過(guò)高階組件包裹的組件在使用時(shí)無(wú)法通過(guò)ref正確獲取到對(duì)應(yīng)的值。二是基礎(chǔ)組件的靜態(tài)方法也會(huì)因?yàn)楦唠A組件的包裹會(huì)丟失。不過(guò)好在這段源碼已經(jīng)給我們提供了對(duì)應(yīng)的解決方案。因此如果我們?cè)谑褂弥行枰幚磉@2點(diǎn)的話,按照這里的方式來(lái)做就可以了。

但是通常情況下,我們也很少會(huì)在自定義的組件中添加靜態(tài)方法和使用ref。如果在開發(fā)中確實(shí)遇到了必須使用它們,就一定要注意高階組件的這2個(gè)問(wèn)題并認(rèn)真解決。

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/83704.html

相關(guān)文章

  • react進(jìn)階系列 - 高階組件詳解四:高階組件的嵌套使用

    摘要:前面有講到過(guò)很多頁(yè)面會(huì)在初始時(shí)驗(yàn)證登錄狀態(tài)與用戶角色。這個(gè)時(shí)候就涉及到一個(gè)高階組件的嵌套使用。而每一個(gè)高階組件函數(shù)執(zhí)行之后中所返回的組件,剛好可以作為下一個(gè)高階組件的參數(shù)繼續(xù)執(zhí)行,而并不會(huì)影響基礎(chǔ)組件中所獲得的新能力。 前面有講到過(guò)很多頁(yè)面會(huì)在初始時(shí)驗(yàn)證登錄狀態(tài)與用戶角色。我們可以使用高階組件來(lái)封裝這部分驗(yàn)證邏輯。封裝好之后我們?cè)谑褂玫臅r(shí)候就可以如下: export default w...

    LMou 評(píng)論0 收藏0
  • react進(jìn)階系列高階組件詳解(三)

    摘要:在前端基礎(chǔ)進(jìn)階八深入詳解函數(shù)的柯里化一文中,我有分享柯里化相關(guān)的知識(shí)。雖然說(shuō)高階組件與柯里化都屬于比較難以理解的知識(shí)點(diǎn),但是他們組合在一起使用時(shí)并沒(méi)有新增更多的難點(diǎn)。 可能看過(guò)我以前文章的同學(xué)應(yīng)該會(huì)猜得到當(dāng)我用New的方法來(lái)舉例學(xué)習(xí)高階組件時(shí),接下來(lái)要分享的就是柯里化了。高階組件與函數(shù)柯里化的運(yùn)用是非常能夠提高代碼逼格的技巧,如果你有剩余的精力,完全可以花點(diǎn)時(shí)間學(xué)習(xí)一下。 在前端基礎(chǔ)進(jìn)...

    zhangxiangliang 評(píng)論0 收藏0
  • react進(jìn)階系列高階組件詳解(一)

    摘要:創(chuàng)建一個(gè)普通函數(shù)因?yàn)榈拇嬖谒宰兂蓸?gòu)造函數(shù)創(chuàng)建一個(gè)方法在方法中,創(chuàng)建一個(gè)中間實(shí)例對(duì)中間實(shí)例經(jīng)過(guò)邏輯處理之后返回使用方法創(chuàng)建實(shí)例而恰好,高階組件的創(chuàng)建邏輯與使用,與這里的方法完全一致。因?yàn)榉椒ㄆ鋵?shí)就是構(gòu)造函數(shù)的高階組件。 很多人寫文章喜歡把問(wèn)題復(fù)雜化,因此當(dāng)我學(xué)習(xí)高階組件的時(shí)候,查閱到的很多文章都給人一種高階組件高深莫測(cè)的感覺(jué)。但是事實(shí)上卻未必。 有一個(gè)詞叫做封裝。相信寫代碼這么久了,大...

    NervosNetwork 評(píng)論0 收藏0
  • 前端文檔收集

    摘要:系列種優(yōu)化頁(yè)面加載速度的方法隨筆分類中個(gè)最重要的技術(shù)點(diǎn)常用整理網(wǎng)頁(yè)性能管理詳解離線緩存簡(jiǎn)介系列編寫高性能有趣的原生數(shù)組函數(shù)數(shù)據(jù)訪問(wèn)性能優(yōu)化方案實(shí)現(xiàn)的大排序算法一怪對(duì)象常用方法函數(shù)收集數(shù)組的操作面向?qū)ο蠛驮屠^承中關(guān)鍵詞的優(yōu)雅解釋淺談系列 H5系列 10種優(yōu)化頁(yè)面加載速度的方法 隨筆分類 - HTML5 HTML5中40個(gè)最重要的技術(shù)點(diǎn) 常用meta整理 網(wǎng)頁(yè)性能管理詳解 HTML5 ...

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

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

0條評(píng)論

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