2020-03-03-- umiJS

umiJS

  • 插件化
  • 開箱即用
  • 約定式路由
  • https://umijs.org/zh-CN
  • npm i -g umi //全局安裝一下就可以umi dev 開發(fā)使用了

umiJS 有強(qiáng)的約束力

  • src/pages,其實(shí)也可以直接pages特愿,習(xí)慣上還是建議寫上src
  • pages 強(qiáng)約定了放頁面蟆盐,pages/page1历筝,pages/page2脓鹃,這樣命名的組建奋姿,路由就直接是這樣了
  • 首頁的話就直接是 pages/index锄开,強(qiáng)約束。
  • umijs 里面還配置了很多內(nèi)置的腳本称诗,可以直接開發(fā) umi dev 就可以開發(fā)了萍悴,什么都不用配置
  • 包括一些熱拔插,熱啟動(dòng)的功能
  • umi dev 編譯出.umi 文件夾寓免,可以讓上面的pages/page1癣诱,pages/page2,直接打路由可以訪問

打包 umi build

  • 像 umi dev 一樣爽

兩種路由使用方法

  • umijs有兩種路由使用方法
  1. 約定式路由:約定好的文件夾和文件袜香,來代表頁面撕予,umi會(huì)根據(jù)開發(fā)者書寫好的頁面,生成路由配置困鸥;最終會(huì)變成配置式路由嗅蔬。
  2. 配置式路由:直接書寫路由配置文件

約定式路由

  • umi約定,工程中的pages文件夾中存放的是頁面疾就。如果工程包含src目錄澜术,則src/pages是頁面文件夾唉
  • umi約定,頁面的文件名字猬腰,和頁面的路徑鸟废,就是頁面的路由
  • 舉例:pages/a -> 路由就是/a,pages/son/a -> 路由就是/son/a姑荷,非常簡單盒延,非常爽
  • umi約定缩擂,如果的頁面文件名字是index.js,pages/index.js -> 首頁路由 /
  • 子頁面的首頁也是 pages/son/index.js
  • 注意避免文件名和當(dāng)前目錄文件夾名字一樣添寺。否則沖突無法匹配胯盯。
  • umi約定,如果src/layouts目錄存在计露,則該目錄中的index.js表示全局通用的布局博脑,布局中的props.children則表示添加具體的頁面。切換別的路由都會(huì)有這個(gè)通用的布局票罐。
  • umi約定叉趣,如果pages文件夾中,包含_layout.js该押,則它所在目錄以及其所有的子目錄中的頁面疗杉,公用該布局。
  • 404約定蚕礼,pages/404.js中烟具,表示404頁面,匹配不到路由跳到該頁面闻牡;開發(fā)模式中無效

路由跳轉(zhuǎn)

  • umi/Link净赴,使用和NavLink 完全一樣,其實(shí)就是react-router-dom中的Link
  • NavLink罩润, 其實(shí)就是react-router-dom 中的 NavLink
  • 跳轉(zhuǎn)鏈接:導(dǎo)入 umi/Link玖翅、umi/NavLink
  • 代碼、組件中跳轉(zhuǎn)割以,導(dǎo)入umi/router金度,它是個(gè)對象,就是history的一些方法
  • @表示src目錄

獲取路由信息

  • 所有的頁面严沥、布局組件猜极,都會(huì)通過屬性props,收到下面的屬性
  1. match -> react-router的match
  2. history -> react-router的match
  3. match
  4. location
  5. route 路由對應(yīng)的配置
  • 如果要使用pathname之類的消玄,請使用withRouter
  • $id.js 文件名約定參數(shù)跟伏,會(huì)傳到組件的props.match.params.id, 就react的動(dòng)態(tài)路由/:id
  • id.js 參數(shù)就可選了
  • name/id$.js -> /:name/:id

配置式路由

  • 當(dāng)使用配置式路由的時(shí)候,約定式路由會(huì)失效翩瓜,有兩種真實(shí)用方式
  1. 項(xiàng)目根目錄下的文件.umirc.js受扳,他是umijs的配置,里面有個(gè)routes:[]
export default {
  routes:[
    {   
        title:"首頁"
        path:"/"
        component: "./index" //相對于pages路徑配置的兔跌,pages/index
        exact:false
        routes:[
            //包子路由 {...}
            ".src/routes/Private.js", ".src/routes/b.js" //這種可以實(shí)現(xiàn)路由權(quán)限
        ]
    }
  ]
}
  • 每個(gè)路由配置都可以添加任何屬性
  1. 項(xiàng)目根目錄下的config/config.js
  • 看官網(wǎng)

使用dva

  • dva模型勘高,作為一個(gè)umi的一個(gè)插件
  • dva 是管理redux的插件
  • 官方插件集 umi-piugin-react
  • 使用umi插件在.umirc.js
  • dva插件和umi整合后,將模型分為兩種:
  1. 全局模型:所有頁面通用,工程一開始啟動(dòng)后华望,模型就會(huì)掛載到倉庫
  • 定義全局模型蕊蝗,約定在src/models 目錄下,模型的命名空間和文件名一致
    // dva 寫法赖舟,組件connect 之后蓬戚,dispatch({ type:"counter/delete" })
    export default {
        state:0,           // counter.js
        reducers:{
            delete(state){ // type:"counter/delete"
                return state - 1
            },
            add(state){
                return state + 1
            }
        }
        effects: {
            *update(action, sageEffects){
                // 這里是一些邏輯
                // 副作用處理用 sageEffects 指令
            }
        }
    }
  1. 局部模型:只能被某些頁面使用,訪問具體的頁面時(shí)才會(huì)掛載到倉庫
  • 定義局部模型建蹄,約定是pages文件夾下碌更,在哪里定義,哪里的頁面就會(huì)動(dòng)態(tài)加載該模型
  • 開發(fā)模式全都能看見的洞慎,局部模型有點(diǎn)像多組件的state的上提,但是嘿棘,它是單鏈?zhǔn)降木⑼龋芟蛏险?/li>
  • 單model.js,

樣式

  1. 保證類樣式名稱的唯一性:css-module / BEM
  • umi 使用了webpack鸟妙,的css-loader加載器焦人,內(nèi)部包含了css-module
  • css文件 -> css-module -> 對象,導(dǎo)入的時(shí)候直接用導(dǎo)入的對象的key
  • import styles from "./a.css"
  • 不共享樣式通常放同一個(gè)目錄即可
  • 共享放assets/css文件夾中重父,盡量以button.css 這樣子放會(huì)好點(diǎn)花椭,維護(hù)性好
  1. 樣式代碼的重復(fù) less
  • less 天生支持,less文件 -> less-loader -> css代碼 -> css-loader(開啟了module) -> 對象

代理和數(shù)據(jù)模擬

  1. 代理
  • 一般用于解決development模式的跨域
  • .umirc.js 配置proxy
  1. 數(shù)據(jù)模擬
  • 解決前后端協(xié)同開發(fā)的問題房午,umi是一個(gè)企業(yè)級別的腳手架矿辽,什么都做好了,開箱即用
  • mock模塊郭厌,模擬數(shù)據(jù)袋倔,無需管后端

umi 約定的mock

  1. mock文件夾中的文件
  2. src/pages文件夾中的_mock.js文件
  • 以上兩種js文件,均會(huì)被umijs讀取折柠,并作為數(shù)據(jù)模擬的配置
  • 開發(fā)完把文件名字一改宾娜,就可以了。
  • 甚至可以自行發(fā)揮扇售,添加模擬數(shù)據(jù)前塔,mockjs庫
  • 建議使用mockjs庫,方便快捷; http://mockjs.com/

dva

  • https://dvajs.com/guide/
  • 寫業(yè)務(wù)代碼的時(shí)候action 和 reducers 模版代碼太重了承冰,dva就很好的把這兩個(gè)東西激進(jìn)的整合起來了华弓。
  • dva不僅僅是一個(gè)第三方庫,更是一個(gè)框架巷懈。它主要整合了redux的相關(guān)內(nèi)容该抒,讓我們方便處理數(shù)據(jù)
  • dva 依賴 react、react-router、redux凑保、redux-saga冈爹、react-redux、connected-react-router
  • dva 把這些東西都整合起來欧引,使用起來非常舒服
  • https://dvajs.com/guide/concepts.html#數(shù)據(jù)流向

初始化dva

    import React from "react"
    import dva from "dva"
    const App = (props) => {
        return(
            <div>
                網(wǎng)站根App
            </div>)
    }
    // 得到一個(gè)dva對象
    const app = dva()

    // 啟動(dòng)之前定義一個(gè)模型芝此,redux-saga/action/reducer 整合在一起
    // 必須在啟動(dòng)之前
    app.model({
        namespace:"student",   //不能缺省憋肖,倉庫名。
        state:{                //默認(rèn)值
        total:0,
        datas:[]
        },
        reducers:{             //reducer婚苹,dva會(huì)自動(dòng)合并
        // dva 約定岸更,方法的名字,就是具體action type
        // 組件使用dva下的connect鏈接膊升,跟以前一樣的用法    
        delete(state, action){
            //以前同步的邏輯
            return {...state}  //注意 immer 數(shù)據(jù)寫法
        },
        },
        effects:{              //副作用怎炊,底層redux-saga,方法的名字就是觸發(fā)的action
        /**
            * @param {*} action 
            * @param {*} sagaEffect redux-saga 對象
            *  {
            *     put({type:'delete'}) //重新觸發(fā)自己的action廓译,不用加前綴
            *     ...還有很多方法评肆,查文檔
            *  }
            */
        *asyncAdd(action, sagaEffect){
            // 這里推薦ES6 開發(fā),阮老師的ES6
            // https://es6.ruanyifeng.com/#docs/generator
        }
        },
        /**
         * 每個(gè)對象是一個(gè)函數(shù)非区,訂閱者瓜挽。
         * 加入store的時(shí)候執(zhí)行一次
         */
        subscriptions:{
        func1(obj){
            //處理一些訂閱事件,因?yàn)樗贿\(yùn)行一次征绸,非常適合訂閱一些事件
            //比如注冊一些特別的事件
            //obj.dispatch({type:'delete'})  
        }
        }
    })

    // 設(shè)置啟動(dòng)后的根路由,
    app.router(() => <App/>)
    // 該函數(shù)傳入一個(gè)選擇器久橙,相當(dāng)于document.getElementById("root")
    app.start("#root")

組件使用dva

    import React from "react"
    import { connect } from "dva"

    const Test = (props) => {
        return(
            <div>
                網(wǎng)站根App
            </div>)
    }
    const mapStateToProps = (state) => ({
        total:state.student.total
    });

    const mapDispatchToProps = (dispatch) => ({
        // 傳入的props方法以on開頭。注意加命名空間
        onDelete:() => dispatch({type:"student/delete", playload:1})
    })

    export default connect(mapStateToProps, mapDispatchToProps)(Test)

Generator 函數(shù)的語法

  • https://es6.ruanyifeng.com/#docs/generator
  • Generator 生成器
  • 由構(gòu)造函數(shù) Generator 創(chuàng)建的對象歹垫,該對象即是一個(gè)迭代器剥汤,同時(shí),又是一個(gè)可迭代對象
  // 偽代碼排惨,Generator 是js引擎的用的吭敢,外部不能用
  // 注意不能箭頭函數(shù),箭頭函數(shù)沒有this 
  var g = new Generator()
  // 迭代器
  g.next()
  // 它也是一個(gè)可迭代對象
  // for of   
  var iterator = g[Symbol.iterator]; 
  1. 生成器函數(shù)暮芭,該函數(shù)用于創(chuàng)建一個(gè)生成器
   //function *func1
   function* create(){

   }
   //生成器函數(shù)create調(diào)用后鹿驼,返回的一定是一個(gè)生成器,而函數(shù)體里面的代碼不會(huì)執(zhí)行
   //函數(shù)體的代碼是生成器控制執(zhí)行的    
   var g = create()    
  1. 每當(dāng)調(diào)用一次生成器的next方法辕宏,生成器的函數(shù)體會(huì)從上次的yield的位置(或開始位置)運(yùn)行到下一個(gè)yield畜晰, yield只能在生成器函數(shù)里面使用。
  2. yield 表達(dá)式返回的數(shù)據(jù)瑞筐,會(huì)當(dāng)做當(dāng)前迭代的數(shù)據(jù)凄鼻,提前return 會(huì)提前done:true
  3. 生成器的返回值,是結(jié)束后的返回值,一旦結(jié)束后繼續(xù)next()块蚌,
  • 都是{ value:undefined, done:false }
   function* create(){
     console.log("kaishi")
     yield;     //g.next() -> { value:undefined, done:false }
     yield 1;   //g.next() -> { value:1, done:false }
     return 2;  //g.next() -> { value:2, done:true }     
   }  
   var g = create()  
  1. 生成器調(diào)用next的時(shí)候闰非,可以傳遞參數(shù),該參數(shù)會(huì)作為生成器函數(shù)體上一次yield表達(dá)式的值
  • 注意 yield getPromise()峭范;不管getPromise邏輯怎么樣财松,返回的啥,yield得到的就是啥
   function* create(){
     console.log("開始")  
     //將 1 作為這次的迭代結(jié)果纱控,等待第二次next辆毡,result才是1 
     //每次會(huì)卡在yield等待你 next() 走
     //yield 受外面控制的,next() 才往下走甜害,參數(shù)是yield的返回值
     let result = yield 1;          // 等待舶掖,我的返回值是上次next(b)中的b    
     console.log("yield 1", result) // yield 1, b
     result = yield 2;              // 等待,我的返回值是上次next(c)中的c 
     console.log("yield 2", result) // yield 2, c
     result = yield 3;              // 等待唾那,我的返回值是上次next(d)中的d 
     console.log("yield 3", result) // yield 3, d
     //yield + 1 = 4 次就完成了访锻,后面再next都是 { value:undefined, done:true } 
   }  
   var g = create() 
   g.next("a") // 第一次傳參無任何意義 { value:1, done:false }
   g.next("b") // { value:2, done:false }
   g.next("c") // { value:3, done:false }
   g.next("d") // { value:undefined, done:true }
  1. 如果生成器函數(shù)嵌套生成器函數(shù),如果單單只是寫執(zhí)行闹获,沒有任何作用
   function* g2(){}
   function* create(){
     console.log("開始")  
     let result = yield 1;          // 等待,我的返回值是上次next(b)中的b    
     console.log("yield 1", result) // yield 1, b
     result = yield 2;              // 等待河哑,我的返回值是上次next(c)中的c 
     g2();                //沒有任何反映避诽,想下為什么?
     result = yield* g2() //這樣才會(huì)進(jìn)入這個(gè)生成器璃谨。result是g2的返回值  
     console.log("yield 2", result) // yield 2, c
     result = yield 3;              // 等待沙庐,我的返回值是上次next(d)中的d 
     console.log("yield 3", result) // yield 3, d
     //yield + 1 = 4 次就完成了,后面再next都是 { value:undefined, done:true } 
   }  
   var g = create() 
   g.next("a") 
   g.next("b") 
   g.next("c") 
   g.next("d") 

redux-saga

  1. 最開始的時(shí)候會(huì)啟動(dòng)一個(gè)saga任務(wù),其實(shí)就是生成器函數(shù)底扳,因?yàn)橥獠靠煽刂郑挥玫鹊絘ction
  2. saga任務(wù)提供了很多任務(wù)指令,可以通過指令控制它的運(yùn)行衷模,說白了就是通過指令來控制redux流程
  3. sage任務(wù)就是一個(gè)生成器函數(shù)
function* task(){ console.log('啟動(dòng)了') }
const sagaMid = createSagaMiddleware()
// store 后面運(yùn)行
sagaMid.run(task) //啟動(dòng)了生成器鹊汛,生成器就受外面控制了
  1. 一般會(huì)把生成器函數(shù)放在saga文件夾
    function* task(){ 
        console.log('啟動(dòng)了')
        yield 3; // yield 普通數(shù)字沒什么意義,會(huì)立即調(diào)用阱冶,同步代碼一樣
        yield `saga effects`; //放的是saga指令刁憋,會(huì)特殊處理,控制整個(gè)流程
    }
  1. saga effects
  • 再次強(qiáng)調(diào)木蹬,saga中至耻,yield 后面如果是個(gè)Promise,saga會(huì)等待完成把值返回到下次next
  • 如果Promise reject 失敗了,會(huì) throw 出錯(cuò)誤尘颓,要try catch 一下
  • 指令前面必須使用yield走触,才會(huì)被saga控制
  • 每個(gè)指令本質(zhì)上就是一個(gè)函數(shù),該函數(shù)調(diào)用后泥耀,會(huì)返回一個(gè)指令對象饺汹,saga 會(huì)接受指令特殊處理
  • {value:'saga effects', done:false},內(nèi)部是這樣處理的
  • take指令:監(jiān)聽某個(gè)action痰催,只監(jiān)聽一次兜辞。yield 得到的是完整的action對象,take(actionTypes.a)
  • all:等待多個(gè)生成器夸溶,完成才會(huì)下一步 all([task1(), task1()])
  • takeEvery:死循環(huán) take指令逸吵;takeEvery(actionTypes.a, task1())
  • delay: 阻塞action,指定毫秒數(shù)
  • put:重新觸發(fā)action缝裁,相當(dāng)于一個(gè)dispatch扫皱;put(action())
  • call:用于副作用函數(shù)調(diào)用,通常是異步的
  • apply:和call作用完全一樣
  • select:用于得到當(dāng)期倉庫的數(shù)據(jù)
  • cps: 用于傳統(tǒng)的回調(diào)寫法捷绑,node.js標(biāo)準(zhǔn)風(fēng)格的異步回調(diào)
  • 更多的指令還是得看文檔
    function* task(){ 
        console.log('啟動(dòng)了')
        yield 3; // yield 普通數(shù)字沒什么意義韩脑,會(huì)立即調(diào)用,同步代碼一樣
        yield takeEvery(actionTypes.a, task()); //放的是saga指令粹污,會(huì)特殊處理段多,控制整個(gè)流程
    }

react hook

  • 原理:
  • hook只能使用在函數(shù)組件
  • 一個(gè)函數(shù)組件可以有很多hook,包括useState的hook壮吩,這樣非常有利于橫切關(guān)注點(diǎn)进苍。

useState:

  1. 運(yùn)行函數(shù)組件時(shí),調(diào)用useState(第一次運(yùn)行)
  2. 檢查一個(gè)狀態(tài)表格
  • 狀態(tài)表格無內(nèi)容
  • 使用默認(rèn)值在表格創(chuàng)建一個(gè)狀態(tài)
  • 將狀態(tài)加入數(shù)組(多個(gè)時(shí)候就加多個(gè))
  1. 重新渲染界面又調(diào)用一次
  • 狀態(tài)表格有內(nèi)容(不需要重新創(chuàng)建了)
  • 忽略默認(rèn)值鸭叙,直接得到狀態(tài)
  1. 表格附著在函數(shù)組件上的觉啊,所以不會(huì)共享狀態(tài)(各有各的狀態(tài)表格)
  • 注意細(xì)節(jié):
  1. useState最好寫在函數(shù)起始位置,方便維護(hù)
  2. useState不能出現(xiàn)在判斷條件if里面沈贝,這樣對維護(hù)表格不利(react根本不讓這么寫)杠人。
  3. useState返回的第二項(xiàng),引用不變缀程,節(jié)省內(nèi)存
  4. 如果使用函數(shù)改變數(shù)據(jù)搜吧,若數(shù)據(jù)和之前的數(shù)據(jù)完全相等(使用Object.is),不會(huì)導(dǎo)致重新渲染杨凑。
  5. 使用函數(shù)改變數(shù)據(jù)滤奈,傳入的值不會(huì)和原來的合并,而是直接替換撩满。(setState是混合的蜒程,可以局部修改)
  6. 也不能直接修改數(shù)據(jù)绅你,和之前類組件一樣。
  7. 如果要強(qiáng)制刷新組件
  • 強(qiáng)制刷新組件昭躺,類組件用forceUpdate()
  • useState直接set一個(gè)空對象就行了,因?yàn)樗歉采w
  1. 和類組件一樣忌锯,組件中改變狀態(tài)可能是異步的(在dom事件中),多個(gè)狀態(tài)會(huì)合并提高效率领炫,此時(shí)偶垮,不能 信任之前的狀態(tài),應(yīng)該使用回調(diào)函數(shù)的方式帝洪。

如果某些狀態(tài)之間沒有必然的聯(lián)系似舵,應(yīng)該切分為不同的狀態(tài),而不要合并成一個(gè)狀態(tài) 因?yàn)榇a耦合度越低葱峡,越好維護(hù)

Effect Hook:用于函數(shù)組件中處理副作用

  • useEffect:接受一個(gè)參數(shù)砚哗,是函數(shù)
  • 副作用:ajax,計(jì)時(shí)器砰奕,更改dom對象蛛芥,以及其它會(huì)對外部產(chǎn)生影響的部分。類組件的時(shí)候军援,涉及服務(wù)端渲染仅淑,除了DidMount,DidUpdate,willUnMount以外其它都會(huì)渲染兩次,盡管react反復(fù)強(qiáng)調(diào)只能在三個(gè)生命周期使用胸哥,但是很多開發(fā)者不遵守漓糙,直接出Effect Hook了。

細(xì)節(jié)

  1. useEffect運(yùn)行的時(shí)間點(diǎn)是頁面真實(shí)dom渲染完成后烘嘱。因此它是異步執(zhí)行的,并且不會(huì)阻塞瀏覽器
  2. 相當(dāng)于類組件的生命鉤子DidMount和DidUpdate蝗蛙,掛載完和更新完
  3. 但是又有區(qū)別的蝇庭,類組件的兩個(gè)生命鉤子更改了真實(shí)的dom,但是用戶沒有看到UI界面捡硅,同步的
  4. useEffect中的副作用函數(shù)哮内,更改了真實(shí)的dom,并且用戶已經(jīng)看到了UI更新壮韭,異步的北发。不會(huì)阻塞界面
  5. 每個(gè)函數(shù)組件中可以多次使用,但是也不能放在判斷或循環(huán)等代碼塊中喷屋,和useState一樣琳拨,后面的hook基本一致
  6. useEffect是有返回值的,返回的是一個(gè)清理函數(shù)屯曹,函數(shù)的運(yùn)行時(shí)間點(diǎn)是每次運(yùn)行副作用的函數(shù)之前狱庇,首次渲染組件不會(huì)運(yùn)行惊畏。組件銷毀時(shí),一定會(huì)運(yùn)行密任。
  7. 重新渲染組件的時(shí)候颜启,不想重新運(yùn)行副作用函數(shù),可以使用第二個(gè)參數(shù)浪讳,這個(gè)參數(shù)是數(shù)組缰盏,然后副作用函數(shù)就依賴這個(gè)數(shù)組,只有依賴的數(shù)據(jù)和上一次不一樣時(shí)淹遵,才會(huì)運(yùn)行執(zhí)行第一個(gè)副作用函數(shù)參數(shù)口猜。
  8. 所以當(dāng)傳遞了依賴數(shù)據(jù)之后,如果數(shù)據(jù)沒有變化 8.1 副作用函數(shù)僅在第一次渲染后運(yùn)行 8.2 清理函數(shù)僅在卸載組件后運(yùn)行
  9. 所以合呐,就可以利用useEffect來實(shí)現(xiàn)之前類組件的掛載運(yùn)行一次暮的,卸載時(shí)運(yùn)行一次。(特別是監(jiān)聽移除dom事件)
  10. 如果依賴項(xiàng)使用的是空數(shù)組淌实,清理函數(shù)就沒有作用了冻辩,但是卸載還是會(huì)運(yùn)行一次
  11. 副作用函數(shù)中,如果使用了函數(shù)組件上下文的變量拆祈,由于閉包的影響重贺,會(huì)導(dǎo)致副作用函數(shù)中變量不會(huì)實(shí)時(shí)變化。js的知識(shí)點(diǎn)伏恐。
  12. 如果副作用函數(shù)在每次注冊時(shí)亿傅,會(huì)覆蓋之前的副作用函數(shù),因此淤年,盡量保持副作用函數(shù)穩(wěn)定钧敞,否則控制起來會(huì)比較復(fù)雜。(把副作用函數(shù)抽出去寫麸粮,動(dòng)態(tài)改變)

自定義hook:將一些常用的溉苛、跨組件的hook功能,抽離出去形成一個(gè)函數(shù)弄诲,該函數(shù)就是自定義hook

  • 例如1:很多組件都需要在第一次加載完成之后愚战,獲取所有XXX的數(shù)據(jù)。
  • 放在以前類組件齐遵,只能在掛載完成DidMount請求數(shù)據(jù)寂玲,或者redux。
  • 以前的一些做法:
  1. render props 數(shù)據(jù)一樣梗摇,界面不一樣拓哟,其實(shí)就是傳遞一個(gè)render函數(shù)下去運(yùn)行。
  2. withComponent 高階組件就是把相同的邏輯抽出來留美。
  • 自定義hook細(xì)節(jié):
  1. 函數(shù)名必須以use開頭
  2. 調(diào)用自定義hook函數(shù)時(shí)彰檬,應(yīng)該放到頂層
  3. 自定義hook其實(shí)就是把hook抽成一個(gè)函數(shù)出去伸刃,多個(gè)hook就可以抽多個(gè),橫切關(guān)注點(diǎn)逢倍,用組合compose編程捧颅。
  • render props 數(shù)據(jù)一樣,界面不一樣较雕,其實(shí)就是傳遞一個(gè)render函數(shù)下去運(yùn)行碉哑。withComponet 高階組件就是把相同的邏輯抽出來。

reducer hook

  • 該函數(shù)接受兩個(gè)參數(shù)亮蒋,一個(gè)是state扣典,和action,和redux那一套一樣慎玖。調(diào)用store.dispatch分發(fā)action返回變化后的數(shù)據(jù)贮尖。
// redux:action -> store.dispatch(action.type) -> reducer -> newState -> store
// 通用的reducer hook, 其實(shí)就是一個(gè)store
export default function useReducer(reducer, initState, initFunc) {
    // initFunc是一個(gè)對第二個(gè)參數(shù)進(jìn)行計(jì)算的一個(gè)回調(diào)函數(shù)
    const [state, setState] = useState(initFunc ? initFunc(initState) : initState)
    // 相當(dāng)與store.dispatch
    function dispatch(action){
        const newState = reducer(state, action)
        setState(newState)
    }
    return [state, dispatch]
}
// reducer hook 未來可能會(huì)結(jié)合redux使用

Context hook

  • 獲取上下文數(shù)據(jù),之前的React.createContext()消費(fèi)者也要套一層趁怔。用這個(gè)hook就可以直接返回ctx的值

callback hook

  • 用于得到一個(gè)固定引用值的函數(shù)湿硝,通常用它來優(yōu)化性能
  • 該函數(shù)有兩個(gè)參數(shù):
  1. 函數(shù),useCallback會(huì)固定該函數(shù)的引用润努,只要依賴項(xiàng)沒發(fā)生變化則會(huì)保持之前函數(shù)的地址
  2. 依賴項(xiàng)关斜,也是個(gè)數(shù)組
  • 該函數(shù)返回值:引用相對固定的函數(shù)地址

Memo hook

  • 用于保持一些比較穩(wěn)定的數(shù)據(jù),通常用于性能優(yōu)化铺浇,用法和callback一樣痢畜,只是callback只能固話一個(gè)引用返回。Memo功能強(qiáng)大些鳍侣,可以固化更多東西丁稀。
  • 可以讓一些穩(wěn)定的,高開銷的渲染數(shù)據(jù)避免掉沒有必要的渲染倚聚。
  • 比如說list數(shù)據(jù)不想受點(diǎn)擊事件避免不了的重新渲染二驰,就可以用Memo
  • 為什么會(huì)出Memo callback這樣的API,因?yàn)楹瘮?shù)組件是普通函數(shù)秉沼,它總是被重新渲染,不像類組件那樣有些生命鉤子只渲染一次矿酵。

Ref hook 一個(gè)參數(shù):默認(rèn)值唬复,返回一個(gè)固定的對象。{current:值}

imperativeHandle Hook

useImperativeHandle(ref, () => {
  //如果不給依賴項(xiàng)全肮,則每次運(yùn)行函數(shù)組件都會(huì)調(diào)用該函數(shù)
  //如果使用了依賴項(xiàng)敞咧,則第一次調(diào)用后,則進(jìn)行緩存辜腺,依賴項(xiàng)變化才重新運(yùn)行
  <!-- ref.current = 1 -->
  return 1
}, [])
// 這個(gè)hook休建,主要是用來使用ref轉(zhuǎn)發(fā)的

LayoutEffect Hook

  • useEffect 是在瀏覽器渲染之后運(yùn)行的乍恐,如果用它操作真實(shí)的dom,渲染頁面有時(shí)候會(huì)閃爍测砂,卡屏
  • 真實(shí)渲染之前做一些改動(dòng)茵烈,useLayoutEffect: 完成dom改動(dòng),還沒有呈現(xiàn)給用戶砌些。用法和useEffect一樣呜投。

細(xì)節(jié)

  • 但是應(yīng)該盡量的使用useEffect,因?yàn)樗粫?huì)阻塞頁面渲染存璃,如果出現(xiàn)了問題仑荐,再考慮使用useLayoutEffect

antd pro

  • 整合了很多前端的技術(shù)
  • 阿里的最佳實(shí)踐,基于umi再次整合
  • React/umi/dva/antd
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
禁止轉(zhuǎn)載纵东,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者粘招。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市偎球,隨后出現(xiàn)的幾起案子洒扎,更是在濱河造成了極大的恐慌,老刑警劉巖甜橱,帶你破解...
    沈念sama閱讀 222,000評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件逊笆,死亡現(xiàn)場離奇詭異,居然都是意外死亡岂傲,警方通過查閱死者的電腦和手機(jī)难裆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來镊掖,“玉大人乃戈,你說我怎么就攤上這事∧督” “怎么了症虑?”我有些...
    開封第一講書人閱讀 168,561評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長归薛。 經(jīng)常有香客問我谍憔,道長,這世上最難降的妖魔是什么主籍? 我笑而不...
    開封第一講書人閱讀 59,782評論 1 298
  • 正文 為了忘掉前任习贫,我火速辦了婚禮,結(jié)果婚禮上千元,老公的妹妹穿的比我還像新娘苫昌。我一直安慰自己,他們只是感情好幸海,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,798評論 6 397
  • 文/花漫 我一把揭開白布祟身。 她就那樣靜靜地躺著奥务,像睡著了一般。 火紅的嫁衣襯著肌膚如雪袜硫。 梳的紋絲不亂的頭發(fā)上氯葬,一...
    開封第一講書人閱讀 52,394評論 1 310
  • 那天,我揣著相機(jī)與錄音父款,去河邊找鬼溢谤。 笑死,一個(gè)胖子當(dāng)著我的面吹牛憨攒,可吹牛的內(nèi)容都是我干的世杀。 我是一名探鬼主播,決...
    沈念sama閱讀 40,952評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼肝集,長吁一口氣:“原來是場噩夢啊……” “哼瞻坝!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起杏瞻,我...
    開封第一講書人閱讀 39,852評論 0 276
  • 序言:老撾萬榮一對情侶失蹤所刀,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后捞挥,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體浮创,經(jīng)...
    沈念sama閱讀 46,409評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,483評論 3 341
  • 正文 我和宋清朗相戀三年砌函,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了斩披。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,615評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡讹俊,死狀恐怖垦沉,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情仍劈,我是刑警寧澤厕倍,帶...
    沈念sama閱讀 36,303評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站贩疙,受9級特大地震影響讹弯,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜这溅,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,979評論 3 334
  • 文/蒙蒙 一闸婴、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧芍躏,春花似錦、人聲如沸降狠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至否纬,卻和暖如春吕晌,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背临燃。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評論 1 272
  • 我被黑心中介騙來泰國打工睛驳, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人膜廊。 一個(gè)月前我還...
    沈念sama閱讀 49,041評論 3 377
  • 正文 我出身青樓乏沸,卻偏偏與公主長得像,于是被迫代替她去往敵國和親爪瓜。 傳聞我的和親對象是個(gè)殘疾皇子蹬跃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,630評論 2 359

推薦閱讀更多精彩內(nèi)容