React學習筆記_無狀態組件(Stateless Component) 與高階組件

來源:互聯網
上載者:User
無狀態組件(Stateless Component) 與高階組件

無狀態組件(Stateless Component) 是 React 0.14 之後推出的,大大增強了編寫 React 組件的方便性,也提升了整體的渲染效能。 一、無狀態組件 (Stateless Component)

function HelloComponent(props, /* context */) {  return <div>Hello {props.name}</div>}ReactDOM.render(<HelloComponent name="Sebastian" />, mountNode)

HelloComponent 第一個參數是 props,第二個是 context。最後一句也可以這麼寫:

ReactDOM.render(HelloComponent{ name:"Sebastian" }, mountNode)

可以看到,原本需要寫“類”定義(React.createClass 或者 class YourComponent extends React.Component)來建立自己組件的定義,現在被精簡成了唯寫一個 render 函數。更值得一提的是,由於僅僅是一個無狀態函數,React 在渲染的時候也省掉了將“組件類” 執行個體化的過程。

結合 ES6 的解構賦值,可以讓代碼更精簡。例如下面這個 Input 組件:

function Input({ label, name, value, ...props }, { defaultTheme }) {  const { theme, autoFocus, ...rootProps } = props  return (    <label      htmlFor={name}      children={label || defaultLabel}      {...rootProps}    >    <input      name={name}      type="text"      value={value || ''}      theme={theme || defaultTheme}      {...props}    />  )}Input.contextTypes = {defaultTheme: React.PropTypes.object};

這個 Input 組件(僅僅是樣本)直接實現了 label/inputText 的組合: defaultTheme 是從 Context 中解構出來的,如果 props 沒有設定 theme,就將用 defaultTheme 替代。 autoFocus 需要被傳遞到底層的 inputText 而不能同時遺留給 label,因此會先通過 { theme, autoFocus, ...rootProps } = props 拿出來。

無狀態組件用來實現 Server 端渲染也很方便,只要避免去直接存取各種 DOM 方法 二、無狀態組件與組件的生命週期方法

我們可以看到,無狀態組件就剩了一個 render 方法,因此也就沒有沒法實現組件的生命週期方法,例如 componentDidMount, componentWillUnmount 等。那麼如果需要讓我們的 Input 組件能夠響應視窗大小的變化,那麼該如何?呢。這其實還是要引入“有狀態的組件”,只不過這個“有狀態的組件”可以不僅僅為 "Input" 元件服務。

const ExecutionEnvironment = require('react/lib/ExecutionEnvironment')let viewport = { width: 1366, height: 768 }; // Default size for server-side renderingfunction handleWindowResize() {  if (viewport.width !== window.innerWidth || viewport.height !== window.innerHeight) {    viewport = { width: window.innerWidth, height: window.innerHeight }  }}function withViewport(ComposedComponent) {  return class Viewport extends React.Component {    state = {      // Server 端渲染和單元測試的時候可未必有 DOM 存在      viewport: ExecutionEnvironment.canUseDOM ?         { width: window.innerWidth, height: window.innerHeight } : viewport    }    componentDidMount() {      // Server 端渲染是不會執行到 `componentDidMount` 的,只會執行到 `componentWillMount`      window.addEventListener('resize', handleWindowResize)      window.addEventListener('orientationchange', handleWindowResize)    }    componentWillUnmount() {      window.removeEventListener('resize', handleWindowResize)      window.removeEventListener('orientationchange', handleWindowResize)    }    render() {      return <ComposedComponent {...this.props} viewport={this.state.viewport}/>    }  }}

那麼,下面我們就可以建立出一個有機會響應視窗大小變化的 Input 組件:

const SizeableInput = withViewport(Input)ReactDOM.render(<SizeableInput name="username" label="Username" {...props} />, mountNode)

withViewort 作為一個 "高階組件" 可不僅僅是為了 Input 服務的。它可以為你需要的任何組件添加上 viewport 屬性,當視窗大小變化時,觸發重繪。

如果你用過 Redux,那麼應該也熟悉 "connect decorator" 的用法。"connect decorator" 也是一個高階組件,因此,你可以繼續來“拼湊”:

const UserNameInput = connect(  state => ({ value: state.username }))(SizeableInput)

高階組件的存在有兩個好處: 當寫著寫著無狀態組件的時候,有一天忽然發現需要狀態處理了,那麼無需徹底返工:) 往往我們需要狀態的時候,這個需求是可以重用的,例如上面的 withViewport,今後可以用來給其他組件(無論是否是無狀態組件)添加 viewport 屬性。

高階組件加無狀態組件,則大大增強了整個代碼的可測試性和可維護性。同時不斷“誘使”我們寫出組合性更好的代碼。 三、無狀態組件不支援 "ref"

有一點遺憾的是無狀態組件不支援 "ref"。原理很簡單,因為在 React 調用到無狀態組件的方法之前,是沒有一個執行個體化的過程的,因此也就沒有所謂的 "ref"。

ref 和 findDOMNode 這個組合,實際上是打破了父子組件之間僅僅通過 props 來傳遞狀態的約定,是危險且骯髒,需要避免。 四、無狀態組件尚不支援 babel-plugin-react-transform 的 Hot Module Replacement

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.