[翻译]React组件模式
作者:William Whatley
摘要:本文介紹了4種組件類型:容器組件、展示組件、高階組件和渲染回調(diào)。
今天,我想花一點時間來分享我學習React組件模式的經(jīng)驗。這個想法來源于一次聚會時的技術交流。組件是React的核心,因此有必要去理解如何使用它們。
以下的例子都脫胎于Michael Chan gave on React component patterns這個視頻的思想。我非常推薦你們看一看。
什么是組件?
reactjs.org上說:“組件能夠將你的界面分割成獨立且可復用的小塊,而這些小組件都是互相獨立的。”
當你第一次執(zhí)行npm install react命令的時候,你得到了一個組件以及相關的API。與JS的函數(shù)類似,一個組件接收輸入,叫做props。然后返回React元素,作用是描述UI界面的樣式。這就是React作為聲明式API的表現(xiàn)形式,因為你只需要告訴它你想要展示的UI,剩下的React都會幫你完成。
對于聲明式API的概念,你可以想象成滴滴打車的場景——告訴司機你的目的地,接著讓他來完成開車的工作。而命令式API不同,你將完成所有任務,既是乘客,也是司機。
組件API
當你在安裝好React后,得到了5類API:
- render
- state
- props
- context
- lifecycle events
盡管寫組件時可以把上面所有的API都使用一遍,但是你很快會發(fā)現(xiàn)一些組件只需要用到某些API,而另一些組件也只會使用另一些特定的API。而這兩類組件往往被劃分為有狀態(tài)與無狀態(tài)組件兩大類。有狀態(tài)的組件會有代表性地使用有狀態(tài)API:render、state和生命周期。但無狀態(tài)組件只會使用render、props和context。
以上就是我們在介紹組件模式前所需要的知識鋪墊。組件模式是設計組件的最佳實踐,最初是把組件切割成數(shù)據(jù)/邏輯層和UI/展示層。通過拆分組件的職責,能夠設計出更容易復用、更內(nèi)聚的組件,從而組裝成復雜的UI界面。這個特性對于構建可擴展的應用時是非常重要的。
組件模式
常用的組件模式有:
- 容器組件
- 展示組件
- 高階組件HOC
- 渲染回調(diào)
容器組件
“容器組件的作用是獲取數(shù)據(jù)和渲染子組件。”——Jason Bonta
容器組件使用了有狀態(tài)的API,封裝了數(shù)據(jù)邏輯層。通過使用生命周期,你可以連接Redux或Flux等狀態(tài)管理庫,然后把數(shù)據(jù)和回調(diào)函數(shù)當作props傳遞給子組件。在容器組件的render方法中,你可以用子展示組件來拼裝UI界面。容器組件往往都設計成一個類組件,而不是純函數(shù)組件,為的就是能夠使用所有有狀態(tài)的API。
在下面的例子中,我們有一個名為Greeting的有狀態(tài)的類組件,包括componentDidMount()和render方法。
class Greeting extends React.Component {constructor() {super();this.state = {name: "",};}componentDidMount() {// AJAXthis.setState(() => {return {name: "William",};});}render() {return (<div><h1>Hello! {this.state.name}</h1></div>);} }這時,這個組件僅僅是一個有狀態(tài)的類組件。為了讓它成為一個真正的容器組件,我們要把UI部分放進一個展示組件中。下面就來講講展示組件。
展示組件
展示組件使用到props、render和context這些無狀態(tài)API,并且可以寫成更簡潔優(yōu)雅的函數(shù)式無狀態(tài)組件。
const GreetingCard = (props) => {return (<div><h1>Hello! {props.name}</h1></div>) }展示組件只能從父級組件或容器組件傳來的props中接收數(shù)據(jù)和回調(diào)函數(shù)。
容器組件和展示組件合并起來后,封裝成了一個真正被使用的組件:
const GreetingCard = (props) => {return (<div><h1>{props.name}</h1></div>) }class Greeting extends React.Component {constructor() {super();this.state = {name: "",};}componentDidMount() {// AJAXthis.setState(() => {return {name: "William",};});}render() {return (<div><GreetingCard name={this.state.name} /></div>);} }如你所見,我把Greeting類組件中的UI部分移除,放入一個無狀態(tài)的函數(shù)組件中。當然,這只是一個簡單的例子,但對于復雜的應用來說,這是最基本的做法。
高階組件(HOC)
高階組件就是一個把組件當作參數(shù),并且返回新組件的函數(shù)。
它的強大之處在于能夠給任意數(shù)量的組件提供數(shù)據(jù)源,并且可以被用來實現(xiàn)邏輯復用。用react-router-v4或Redux舉個例子。使用react-router-v4時,你可以使用withRouter()來繼承傳給組件的props。而使用Redux時,你通過使用connect({})()來把actions當作props傳遞給子組件。
看看這個例子:
import {withRouter} from 'react-router-dom';class App extends React.Component {constructor() {super();this.state = {path: ''}}componentDidMount() {let pathName = this.props.location.pathname;this.setState(() => {return {path: pathName,}})}render() {return (<div><h1>Hi! I'm being rendered at: {this.state.path}</h1></div>)} }export default withRouter(App);當導出我的組件時,我使用react-router-v4提供的withRouter()方法把它包裹起來。而在App的componentDidMount()生命周期中,我通過this.props.location.pathname來更新狀態(tài)。在被withRouter()包裹后,我的類組件現(xiàn)在可以通過props訪問react-router-v4的方法,就像this.props.location.pathname。像這樣的例子,實在是不勝枚舉。
渲染回調(diào)(render callbacks)
與高階組件類似,渲染回調(diào)或者說渲染props都是用來實現(xiàn)組件邏輯復用功能。相比較于大多數(shù)開發(fā)者使用的高階組件,渲染回調(diào)也有自己的優(yōu)勢。具體優(yōu)勢可以閱讀Michael Jackson所寫的這個視頻——《Never write another HOC.》。視頻中所講的關鍵點就是渲染回調(diào)能夠減少命名空間的沖突并且解釋邏輯的來源。
在上面的Counter類中,我在render里使用了this.props.children,然后把this.state當作參數(shù)傳給這個函數(shù)。之后在App類中,我把想要展示的組件用Counter組件包裹起來,這樣就能使用Counter的代碼邏輯了。render函數(shù)的返回結果是代碼28行,在那里我通過{state => ()}自動獲取到Counter的state。
感謝您的閱讀
我很樂意接受大家的意見來使我成長。我對React組件模式的見解還不夠成熟,所以我也算是在寫作中學習吧。
查看更多我翻譯的Medium文章請訪問:項目地址:https://github.com/WhiteYin/translation
SF專欄:https://segmentfault.com/blog/yin-translation
總結
以上是生活随笔為你收集整理的[翻译]React组件模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: iOS 关于集成融云IM的一些常用方法
- 下一篇: NetCat Tutorials