一.State和Props
state是狀態(tài)機。
應該包括:那些可能被組件的事件處理器改變并觸發(fā)用戶界面更新的數(shù)據(jù),譬如需要對用戶輸入,服務器請求或者時間變化等作出響應。
不應該包括:計算所得數(shù)據(jù)、React組件(在render()里使用props和state來創(chuàng)建它)、基于props的重復數(shù)據(jù)(盡可能保持用props來做作為唯一的數(shù)據(jù)來源,把props保存到state中的有效的場景是需要知道它以前的值得時候,因為未來的props可能會變化)。
props:父級向子級傳遞數(shù)據(jù)的方式。
二.有狀態(tài)組件和無狀態(tài)組件(純函數(shù)組件)
有狀態(tài)組件:
通過React.createClass或者es6的class繼承React.Component創(chuàng)建的組件。
特性:具備完整的生命周期及實例化過程、支持this及ref指向.
無狀態(tài)組件:
即statelesscomponent(pure function Component)。以函數(shù)返回值方式方式創(chuàng)建的組件。
特點:無實例化過程及生命周期、無this及ref指向、函數(shù)接受props及context兩個參數(shù)。
實踐模式
創(chuàng)建多個只負責渲染數(shù)據(jù)的無狀態(tài)(stateless)組件,在他們的上層創(chuàng)建一個有狀態(tài)(stateful)組件并把它的狀態(tài)通過props傳給子級。有狀態(tài)的組件封裝了所有的用戶交互邏輯,state中處理狀態(tài)的變化,而這些無狀態(tài)組件只負責聲明式地渲染數(shù)據(jù).
三.受控組件、非受控組件及混合組件
有許多的web組件可以被用戶的交互發(fā)生改變,比如:<input>,<select>。這些組件可以通過輸入一些內容或者設置元素的value屬性來改變組件的值。但是,因為React是單向數(shù)據(jù)流綁定的,這些組件可能會變得失控:
1.一個維護它自己state里的value值的<Input>組件無法從外部被修改
2.一個通過props來設置value值的<Input>組件只能通過外部控制來更新。
受控組件:
一個受控的<input>應該有一個value屬性。渲染一個受控的組件會展示出value屬性的值。一個受控的組件不會維護它自己內部的狀態(tài),組件的渲染單純的依賴于props。也就是說,如果我們有一個通過props來設置value的<input>組件,不管你如何輸入,它都只會顯示props.value。換句話說,你的組件是只讀的。在處理一個受控組件的時候,應該始終傳一個value屬性進去,并且注冊一個onChange的回調函數(shù)讓組件變得可變.
非受控組件:
一個沒有value屬性的<input>就是一個非受控組件。通過渲染的元素,任意的用戶輸入都會被立即反映出來。非受控的<input>只能通過OnChange函數(shù)來向上層通知自己被用戶輸入的更改。
混合組件:
同時維護props.value和state.value的值。props.value在展示上擁有更高的優(yōu)先級,state.value代表著組件真正的值。
目的:
1、支持傳入值;2、可控:組件外部修改props可改變input組件的真實值及顯示值;3、非可控:輸入框中輸入值,可同時改變input組件的真實值及顯示值。
四.redux和dva
Redux
1.Actions、Reducers和Store
action可以理解為應用向store傳遞的數(shù)據(jù)信息(一般為用戶交互信息)。在實際應用中,傳遞的信息可以約定一個固定的數(shù)據(jù)格式,比如:Flux Standard Action。dispatch(action)是一個同步的過程:執(zhí)行reducer更新state->調用store的監(jiān)聽處理函數(shù)。如果需要在dispatch時執(zhí)行一些異步操作(fetch action data),可以通過引入Middleware解決。
reducer實際上就是一個函數(shù):(previousState,action)=>newState。用來執(zhí)行根據(jù)指定action來更新state的邏輯。reducer不存儲state,reducer函數(shù)邏輯中不應該直接改變state對象,而是返回新的state對象。
store是一個單一對象,redux中只有唯一一個store實例。主要作用:
1.管理應用的state
2.通過store.getState()可以獲取state
3.通過store.dispatch(action)來觸發(fā)state更新
4.通過store.subscribe(listener)來注冊state變化監(jiān)聽器
b.Dva
數(shù)據(jù)流向
數(shù)據(jù)的改變發(fā)生通常是通過用戶交互行為或者瀏覽器行為(如路由跳轉等)觸發(fā)的,當此類行為會改變數(shù)據(jù)的時候可以通過dispatch發(fā)起一個action,如果是同步行為會直接通過Reducers改變State,如果是異步行為(副作用)會先觸發(fā)Effects然后流向Reducers最終改變State,所以在dva中,數(shù)據(jù)流向非常清晰簡明,并且思路基本跟開源社區(qū)保持一致(也是來自于開源社區(qū))。
Models
State
type State=any
State表示Model的狀態(tài)數(shù)據(jù),通常表現(xiàn)為一個javascript對象(當然它可以是任何值);操作的時候每次都要當作不可變數(shù)據(jù)(immutabledata)來對待,保證每次都是全新對象,沒有引用關系,這樣才能保證State的獨立性,便于測試和追蹤變化。
在dva中你可以通過dva的實例屬性_store看到頂部的state數(shù)據(jù),但是通常你很少會用到:
Action
typeAsyncAction=any
Action是一個普通javascript對象,它是改變State的唯一途徑。無論是從UI事件、網(wǎng)絡回調,還是WebSocket等數(shù)據(jù)源所獲得的數(shù)據(jù),最終都會通過dispatch函數(shù)調用一個action,從而改變對應的數(shù)據(jù)。action必須帶有type屬性指明具體的行為,其它字段可以自定義,如果要發(fā)起一個action需要使用dispatch函數(shù);需要注意的是dispatch是在組件connect Models以后,通過props傳入的。
dispatch函數(shù)
typedispatch=(a:Action)=>Action
dispatching function是一個用于觸發(fā)action的函數(shù),action是改變State的唯一途徑,但是它只描述了一個行為,而dipatch可以看作是觸發(fā)這個行為的方式,而Reducer則是描述如何改變數(shù)據(jù)的。
在dva中,connect Model的組件通過props可以訪問到dispatch,可以調用Model中的Reducer或者Effects,常見的形式如:
Reducer
typeReducer<S,A>=(state:S,action:A)=>S
Reducer(也稱為reducing function)函數(shù)接受兩個參數(shù):之前已經(jīng)累積運算的結果和當前要被累積的值,返回的是一個新的累積結果。該函數(shù)把一個集合歸并成一個單值。
Reducer的概念來自于是函數(shù)式編程,很多語言中都有reduce API。如在javascript中:
在dva中,reducers聚合積累的結果是當前model的state對象。通過actions中傳入的值,與當前reducers中的值進行運算獲得新的值(也就是新的state)。需要注意的是Reducer必須是純函數(shù),所以同樣的輸入必然得到同樣的輸出,它們不應該產(chǎn)生任何副作用。并且,每一次的計算都應該使用immutabledata,這種特性簡單理解就是每次操作都是返回一個全新的數(shù)據(jù)(獨立,純凈),所以熱重載和時間旅行這些功能才能夠使用。
Effect
Effect被稱為副作用,在我們的應用中,最常見的就是異步操作。它來自于函數(shù)編程的概念,之所以叫副作用是因為它使得我們的函數(shù)變得不純,同樣的輸入不一定獲得同樣的輸出。
dva為了控制副作用的操作,底層引入了redux-sagas做異步流程控制,由于采用了generator的相關概念,所以將異步轉成同步寫法,從而將effects轉為純函數(shù)。至于為什么我們這么糾結于純函數(shù),如果你想了解更多可以閱讀Mostlyadequate guide to FP,或者它的中文譯本JS函數(shù)式編程指南。
Subscription
Subscriptions是一種從源獲取數(shù)據(jù)的方法,它來自于elm。
Subscription語義是訂閱,用于訂閱一個數(shù)據(jù)源,然后根據(jù)條件dispatch需要的action。數(shù)據(jù)源可以是當前的時間、服務器的websocket連接、keyboard輸入、geolocation變化、history路由變化等等。
Router
這里的路由通常指的是前端路由,由于我們的應用現(xiàn)在通常是單頁應用,所以需要前端代碼來控制路由邏輯,通過瀏覽器提供的HistoryAPI可以監(jiān)聽瀏覽器url的變化,從而控制路由相關操作。
dva實例提供了router方法來控制路由,使用的是react-router。
RouteComponents
在組件設計方法中,我們提到過Container Components,在dva中我們通常將其約束為Route Components,因為在dva中我們通常以頁面維度來設計Container Components。
所以在dva中,通常需要connect Model的組件都是Route Components,組織在/routes/目錄下,而/components/目錄下則是純組件(Presentational Components)。
五.hoc
HOC(全稱Higher-ordercomponent)是一種React的進階使用方法,主要還是為了便于組件的復用。HOC就是一個方法,獲取一個組件,返回一個更高級的組件。
在React開發(fā)過程中,發(fā)現(xiàn)有很多情況下,組件需要被"增強",比如說給組件添加或者修改一些特定的props,一些權限的管理,或者一些其他的優(yōu)化之類的。而如果這個功能是針對多個組件的,同時每一個組件都寫一套相同的代碼,明顯顯得不是很明智,所以就可以考慮使用HOC。
一個最簡單的HOC實現(xiàn)是這個樣子的:
HOC可以做什么?
代碼復用,代碼模塊化;
增刪改props;
渲染劫持;
增刪改props;
可以通過對傳入的props進行修改,或者添加新的props來達到增刪改props的效果。
比如你想要給wrappedComponent增加一個props,可以這么搞:
這樣,你就可以在你的組件中使用message這個props:
渲染劫持
這里的渲染劫持并不是你能控制它渲染的細節(jié),而是控制是否去渲染。由于細節(jié)屬于組件內部的render方法控制,所以你無法控制渲染細節(jié)。
比如,組件要在data沒有加載完的時候,現(xiàn)實loading...,就可以這么寫:
這個樣子,在父級沒有傳入data的時候,這一塊兒就只會顯示loading...,不會顯示組件的具體內容
六.項目中的實踐
1.合理使用有狀態(tài)組件及無狀態(tài)組件。在使用redux或者dva的場景下,理論上所有的組件都可以封裝為無狀態(tài)組件(少數(shù)需要生命周期控制或者上文提到的混合式組件除外),model中封裝數(shù)據(jù)、異步effects及同步reducers,通過connect綁定到對應的組件上。
最佳實踐:
router中getcomponent中定義的組件我們稱之為路由組件,一般路由組件會通過connect綁定model中定義的state及組件中定義的方法到該組件的props上。其他方式定義的為非路由組件,非路由組件盡量避免使用connect,而是通過路由組件或者其他上層通過props傳遞數(shù)據(jù)進行渲染。
2.理解subscription,effects及reducers中各自的功能職責。
3.package.json中定義的dependency,需要深入研究,避免重復造輪子。
4.全局觀及合理的組件規(guī)劃。
文章來源:CSDN,作者:天微微亮-zwp;
【數(shù)商云m.zhimaihui.cn】致力于提供企業(yè)級的電子商務系統(tǒng)服務,長期為大中型企業(yè)打造數(shù)據(jù)化、商業(yè)化、智能化的電子商務建設方案,同時我們還提供B2B電子商務平臺、B2B2C多用戶商城系統(tǒng)、B2C電子商務系統(tǒng)、跨境進口電商平臺、供應商管理系統(tǒng)、新零售電商平臺、直播電商系統(tǒng)等一系列系統(tǒng)定制開發(fā)服務。
評論