摘要:事件系統(tǒng)合成事件的綁定方式合成事件的實現(xiàn)機制事件委派和自動綁定。高階組件如果已經(jīng)理解高階函數(shù),那么理解高階組件也很容易的。例如我們常見的方法等都是高階函數(shù)。對測試群眾來說,從質(zhì)量保證的角度出發(fā),單元測試覆蓋率是
事件系統(tǒng)
合成事件的綁定方式
``
合成事件的實現(xiàn)機制:事件委派和自動綁定。
React合成事件系統(tǒng)的委托機制,在合成事件內(nèi)部僅僅是對最外層的容器進行了綁定,并且依賴事件的冒泡機制完成了委派。
表單
React受控組件更新state的流程:
可以通過在初始state中設置表單的默認值。
每當表單的值發(fā)生變化時,調(diào)用onChange事件處理器。
事件處理器通過合成事件對象e拿到改變后的狀態(tài),并更新應用的state。
setState觸發(fā)視圖的重新渲染,完成表單組件值的更新。
受控組件和非受控組件的最大區(qū)別是:非受控組件的狀態(tài)并不會受應用狀態(tài)的控制,應用中也多了局部組件狀態(tài),而受控組件的值來自于組件的state。
樣式處理
CSS模塊化遇到了哪些問題?全局污染,命名混亂,依賴管理不徹底,無法共享變量,代碼壓縮不徹底。
CSS Modules模塊化方案:啟用CSS Modules,樣式默認局部,使用composes來組合樣式。
組件間通信
子組件向父組件通信
利用回調(diào)函數(shù)
利用自定義事件機制
當需要讓子組件跨級訪問信息時,我們還可以使用context來實現(xiàn)跨級父子組件間的通信。
沒有嵌套關系的組件通信:我們在處理事件的過程中需要注意,在componentDidMount事件中,如果組件掛載完成,再訂閱事件;當組件卸載的時候,在componentWillUnmount事件中取消事件的訂閱。
組件間抽象
mixin 的目的,就是為了創(chuàng)造一種類似多重繼承的效果,或者說,組合。實際上,包括C++等一些年齡較大的OOP語言,都有一個強大但是危險的多重繼承特性?,F(xiàn)代語言權衡利弊,大都舍棄了它,只采用單繼承。但是單繼承在實現(xiàn)抽象的時候有很多不便,為了彌補缺失,Java引入接口(interface),其他一些語言則引入了mixin的技巧。
封裝mixin方法
方法:const mixin = function(obj, mixins) { const newObj = obj; newObj.prototype = Object.create(obj.prototype); for (let prop in mixins) { if (mixins.hasOwnProperty(prop)) { newObj.prototype[prop] = mixins[prop]; } } return newObj; }應用:
const BigMixin = { fly: () => { console.log("I can fly"); } }; const Big = function() { console.log("new big"); }; const FlyBig = mixin(Big, BigMixin); const flyBig = new FlyBig(); // => "new big" flyBig.fly(); // => "I can fly"上面這段代碼實現(xiàn)對象混入的方法是:用賦值的方式將mixin對象里的方法都掛載到原對象上。
在React中使用mixin
React在使用createClass構建組件時提供了mixin屬性,比如官方封裝的:PureRenderMixin。
import React from "react"; import PureRenderMixin from "react-addons-pure-render-mixin"; React.createClass({ mixins: [PureRenderMixin], render() { returnfoo; } });在createClass對象參數(shù)中傳入數(shù)組mixins,里面封裝了我們需要的模塊。mixins數(shù)組也可以添加多個mixin。同時,在React中不允許出現(xiàn)重名普通方法的mixin。而如果是生命周期方法,則React將會將各個模塊的生命周期方法疊加在一起然后順序執(zhí)行。
使用createClass實現(xiàn)的mixin為組件做了兩件事:工具方法:這是mixin的基本功能,如果希望共享一些工具類的方法,就可以直接定義它們?nèi)缓笤诮M件中使用。
生命周期繼承,props和state合并。mixin能夠合并生命周期方法。如果有很多mixin來定義componentDidMount這個周期,那么React會很機智的將它們都合并起來執(zhí)行。同樣,mixin也可以作state和props的合并。
ES6 Classes和decorator
然而,當我們使用ES6 classes的形式構建組件的時候,卻并不支持mixin。為了使用這個強大的功能,我們還需要采取其他方法,來達到模塊重用的目的??梢允褂肊S7的語法糖decorator來實現(xiàn)class上的mixin。core-decorators庫為開發(fā)者提供了一些實用的decorator, 其中也正好實現(xiàn)了我們想要的@mixin。
import React, { Component } from "React"; import { mixin } from "core-decorators"; const PureRender = { shouldComponentUpdate() {} }; const Theme = { setTheme() {} }; @mixin(PureRender, Theme) class MyComponent extends Component { render() {} }mixin的問題
破壞了原有組件的封裝:mixin會混入方法,給原有的組件帶來新特性。但同時它也可能帶來新的state和props,這意味著組件有一些“不可見”的狀態(tài)需要我們?nèi)ゾS護。另外,mixin也有可能去依賴其他的mixin,這樣會建立一個mixin的依賴鏈,當我們改動一個mixin的狀態(tài),很有可能也會影響其他的mixin。
命名沖突
增加復雜性
針對這些困擾,React提出的新的方式來取代mixin,那就是高階組件。
高階組件
如果已經(jīng)理解高階函數(shù),那么理解高階組件也很容易的。高階函數(shù):就是一種這樣的函數(shù),它接受函數(shù)作為參數(shù)輸入,或者將一個函數(shù)作為返回值。例如我們常見的方法map, reduce, sort等都是高階函數(shù)。高階組件和和高階函數(shù)很類似,高階組件就是接受一個React組件作為參數(shù)輸入,輸出一個新的React組件。高階組件讓我們的代碼更具有復用性、邏輯性與抽象性,它可以對render方法作劫持,也可以控制props和state。
實現(xiàn)高階組件的方法有如下兩種:屬性代理:高階組件通過被包裹的React組件來操作props。
反向繼承:高階組件繼承于被包裹的React組件。
屬性代理
示例代碼:import React, { Component } from "React"; const MyContainer = (WrappedComponent) => class extends Component { render() { return; } } 在代碼中我們可以看到,render方法返回了傳入的WrappedComponent組件。這樣,我們就可以通過高階組件來傳遞props。這種方式就是屬性代理。
如何使用上面這個高階組件:import React, { Component } from "React"; class MyComponent extends Component { // ... } export default MyContainer(MyComponent);這樣組件就可以一層層的作為參數(shù)被調(diào)用,原始組件久具備了高階組件對它的修飾。這樣,保持單個組件封裝的同時也保留了易用行。
從功能上, 高階組件一樣可以做到像mixin對組件的控制:控制props
我們可以讀取、增加、編輯或是移除從WrappedComponent傳進來的props。
例如:新增propsimport React, { Component } from "React"; const MyContainer = (WrappedComponent) => class extends Component { render() { const newProps = { text: newText, }; return; } } 注意:
// is equivalent to React.createElement(WrappedComponent, this.props, null) 這樣,當調(diào)用高階組件的時候,就可以使用text這個新的props了。
通過refs使用引用
抽象state
高階組件可以講原組件抽象為展示型組件,分離內(nèi)部狀態(tài)。
const MyContainer = (WrappedComponent) => class extends Component { constructor(props) { super(props); this.state = { name: "", 4 }; this.onNameChange = this.onNameChange.bind(this); } onNameChange(event) { this.setState({ name: event.target.value, }) } render() { const newProps = { name: { value: this.state.name, onChange: this.onNameChange, }, } return; } } 在這個例子中,我們把組件中對name prop 的onChange方法提取到高階組件中,這樣就有效的抽象了同樣的state操作。
使用方式@MyContainer class MyComponent extends Component { render() { return ; } }反向繼承
const MyContainer = (WrappedComponent) => class extends WrappedComponent { render() { return super.render(); } }
組件性能優(yōu)化
性能優(yōu)化的思路影響網(wǎng)頁性能最大的因素是瀏覽器的重排(repaint)和重繪(reflow)。React的Virtual DOM就是盡可能地減少瀏覽器的重排和重繪。從React渲染過程來看,如何防止不必要的渲染是解決問題的關鍵。
性能優(yōu)化的具體辦法盡量多使用無狀態(tài)函數(shù)構建組件
無狀態(tài)組件只有props和context兩個參數(shù)。它不存在state,沒有生命周期方法,組件本身即有狀態(tài)組件構建方法中的render方法。在合適的情況下,都應該必須使用無狀態(tài)組件。無狀態(tài)組件不會像React.createClass和ES6 class會在調(diào)用時創(chuàng)建新實例,它創(chuàng)建時始終保持了一個實例,避免了不必要的檢查和內(nèi)存分配,做到了內(nèi)部優(yōu)化。
拆分組件為子組件,對組件做更細粒度的控制
相關重要概念:純函數(shù)
純函數(shù)的三大構成原則:
給定相同的輸入,它總是返回相同的輸出: 比如反例有 Math.random(), New Date();
過程沒有副作用:即不能改變外部狀態(tài);
沒有額外的狀態(tài)依賴:即方法內(nèi)部的狀態(tài)都只能在方法的生命周期內(nèi)存活,這意味著不能在方法內(nèi)使用共享的變量。
純函數(shù)非常方便進行方法級別的測試及重構,它可以讓程序具有良好的擴展性及適應性。純函數(shù)是函數(shù)式變成的基礎。React組件本身就是純函數(shù),即傳入指定props得到一定的Virtual DOM,整個過程都是可預測的。
具體辦法
拆分組件為子組件,對組件做更細粒度的控制。保持純凈狀態(tài),可以讓方法或組件更加專注(focus),體積更小(small),更獨立(independent),更具有復用性(reusability)和可測試性(testability)。
運用PureRender,對變更做出最少的渲染
相關重要概念: PureRender
PureRender的Pure即是指滿足純函數(shù)的條件,即組件被相同的props和state渲染會得到相同的結果。在React中實現(xiàn)PureRender需要重新實現(xiàn)shouldComponentUpdate生命周期方法。shouldComponentUpdate是一個特別的方法,它接收需要更新的props和state,其本質(zhì)是用來進行正確的組件渲染。當其返回false的時候,不再向下執(zhí)行生命周期方法;當其返回true時,繼續(xù)向下執(zhí)行。組件在初始化過程中會渲染一個樹狀結構,當父節(jié)點props改變的時候,在理想情況下只需渲染一條鏈路上有關props改變的節(jié)點即可;但是,在默認情況下shouldComponentUpdate方法返回true,React會重新渲染所有的節(jié)點。
有一些官方插件實現(xiàn)了對shouldComponentUpdate的重寫,然后自己也可以做一些代碼的優(yōu)化來運用PureRender。具體辦法
運用PureRender
使用官方插件react-addons-pure-render-mixin實現(xiàn)對shouldComponentUpdate的重寫
import React from "react"; import PureRenderMixin from "react-addons-pure-render-mixin"; class App extends React.Component { constructor(props) { super(props); this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this); } render() { returnfoo} }它的原理是對object(包括props和state)做淺比較,即引用比較,非值比較。比如只用關注props中每一個是否全等(如果是prop是一個對象那就是只比較了地址,地址一樣就算是一樣了),而不用深入比較。
優(yōu)化PureRender
避免無論如何都會觸發(fā)shouldComponentUpdate返回true的代碼寫法。避免直接為prop設置字面量的數(shù)組和對象,就算每次傳入的數(shù)組或?qū)ο蟮闹禌]有變,但它們的地址也發(fā)生了變化。
如以下寫法每次渲染時style都是新對象都會觸發(fā)shouldComponentUpdate為true:改進辦法:將字面量設置為一個引用:
const defaultStyle = {};避免每次都綁定事件,如果這樣綁定事件的話每次都要生成一個新的onChange屬性的值:
render() { return }該盡量在構造函數(shù)內(nèi)進行綁定,如果綁定需要傳參那么應該考慮抽象子組件或改變現(xiàn)有數(shù)據(jù)結構:
constructor(props) { super(props); this.handleChange = this.handleChange.bind(this); } handleChange() { ... } render() { return }在設置子組件的時候要在父組件級別重寫shouldComponentUpdate。
運用immutable
JavaScript中對象一般是可變的,因為使用引用賦值,新的對象的改變將影響原始對象。為了解決這個問題是使用深拷貝或者淺拷貝,但這樣做又造成了CPU和內(nèi)存的浪費。Immutable data很好地解決了這個問題。Immutable data就是一旦創(chuàng)建,就不能再更改的數(shù)據(jù)。對Immutable對象進行修改、添加或刪除操作,都會返回一個新的Immutable對象。Immutable實現(xiàn)的原理是持久化的數(shù)據(jù)結構。即使用舊數(shù)據(jù)創(chuàng)建新數(shù)據(jù)時,保證新舊數(shù)據(jù)同時可用且不變。同時為了避免深拷貝帶來的性能損耗,Immutable使用了結構共享(structural sharing),即如果對象樹中一個節(jié)點發(fā)生變化,只修改這個節(jié)點和受它影響的父節(jié)點,其他節(jié)點則進行共享。
自動化測試
jest 是 facebook 開源的,用來進行單元測試的框架,功能比較全面,測試、斷言、覆蓋率它都可以,另外還提供了快照功能。
對測試群眾來說,從質(zhì)量保證的角度出發(fā),單元測試覆蓋率100%是否就足夠了呢?肯定不夠??!
結合實際的項目經(jīng)驗來看,jest的測試還可以根據(jù)產(chǎn)品的實際需求,做一些諸如:
點擊某個頁面元素后,需要在頁面上顯示新的區(qū)塊,并且要加載指定的的css的測試;
點擊某個link,需要跳轉到指定的網(wǎng)站的測試;
等等
這些測試原本在UI自動化功能測試中也比較常見,這里我們都可以把它們挪到低層中去。所以具體的測試用例,在單元測試覆蓋率超級高的前提下,我們測試的群眾還可以跟研發(fā)結對完成?;蛘咧笇а邪l(fā)完成,要不干脆自己加上去算了。另外,產(chǎn)品的功能性測試完成的情況下,我們還需要考慮下非功能性的問題,例如兼容性、性能、安全性等。再加上測試金字塔的頂端之上,其實還有探索性測試的位置。產(chǎn)品的基本功能由單元測試保障了,剩下的時間,我們可以做更多的探索性測試了不是嗎?總之,干掉UI自動化功能測試只是一個加速測試反饋周期、減少投入成本的嘗試。軟件的質(zhì)量不僅僅是測試攻城獅的事情,而是整個團隊的責任。堅持一些重要的編碼實踐,比如state less的組件、build security in等,也是提高質(zhì)量的重要手段。
文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/105571.html
摘要:學習之道簡體中文版通往實戰(zhàn)大師之旅掌握最簡單,且最實用的教程。前言學習之道這本書使用路線圖中的精華部分用于傳授,并將其融入一個獨具吸引力的真實世界的具體代碼實現(xiàn)。完美展現(xiàn)了的優(yōu)雅。膜拜的學習之道是必讀的一本書。 《React 學習之道》The Road to learn React (簡體中文版) 通往 React 實戰(zhàn)大師之旅:掌握 React 最簡單,且最實用的教程。 showIm...
摘要:語法將語法直接加入到代碼中,再通過翻譯器裝換到純后由瀏覽器執(zhí)行。事實上,并不需要花精力學習。可以說,基本語法基本被囊括了,但也有少許不同。明確的數(shù)據(jù)流動。這條原則讓組件之間的關系變得簡單且可預測。使用獲取和顯示回調(diào)。 JSX語法 JSX將HTML語法直接加入到JavaScript代碼中,再通過翻譯器裝換到純JavaScript后由瀏覽器執(zhí)行。在實際開發(fā)中,JSX在產(chǎn)品打包階段都已經(jīng)編...
摘要:是用戶建立客戶端應用的前端架構,它通過利用一個單向的數(shù)據(jù)流補充了的組合視圖組件,這更是一種模式而非正式框架,你能夠無需許多新代碼情況下立即開始使用。結構和數(shù)據(jù)流一個單向數(shù)據(jù)流是模式的核心。 Flux是Facebook用戶建立客戶端Web應用的前端架構,它通過利用一個單向的數(shù)據(jù)流補充了React的組合視圖組件,這更是一種模式而非正式框架,你能夠無需許多新代碼情況下立即開始使用Flux。 ...
摘要:根據(jù)的類型不同,分別實例化類。并且處理特殊屬性,比如事件綁定。之后根據(jù)差異對象操作元素位置變動,刪除,添加等。各個組件獨立管理層層嵌套,互不影響,內(nèi)部實現(xiàn)的渲染功能。根據(jù)基本元素的值,判斷是否遞歸更新子節(jié)點,還是刪除舊節(jié)點,添加新節(jié)點。 首先理解ReactElement和ReactClass的概念。想要更好的利用react的虛擬DOM,diff算法的優(yōu)勢,我們需要正確的優(yōu)化、組織rea...
摘要:目前,有三個明確的框架可供選擇。和在眾多開源框架中贏得了開發(fā)人員和公司的信任。雖然這三個框架有許多共同之處,但它們的受歡迎程度因行業(yè)而異。使用,這有助于在編碼時發(fā)現(xiàn)并糾正常見錯誤。 人們首先注意到的是你的應用程序的視覺吸引力。大多數(shù)用戶傾向于將界面設計與公司的信譽和專業(yè)能力聯(lián)系起來。這就是為什么選擇正確的前端技術對你的業(yè)務...
閱讀 2416·2021-11-25 09:43
閱讀 1195·2021-09-07 10:16
閱讀 2603·2021-08-20 09:38
閱讀 2936·2019-08-30 15:55
閱讀 1449·2019-08-30 13:21
閱讀 883·2019-08-29 15:37
閱讀 1435·2019-08-27 10:56
閱讀 2093·2019-08-26 13:45