1. 程式人生 > >React的元件,元素和例項

React的元件,元素和例項

React Components, Elements, and Instances

Elements Describe the Tree

react中,元素(element)就是描述元件例項或DOM節點及其所需屬性的普通物件。 它僅包含有關元件型別(例如,Button元件),
其屬性(例如,顏色)以及其中的任何子元素的資訊。

並且元素也不是實際的元件例項。相反,它是一種告訴React你想在螢幕上看到什麼的方法。
你不能在元素上呼叫任何方法。它只是一個帶有兩個欄位的不可變描述物件:type: (string | ReactClass) && props: Object1

DOM Elements

當元素(element)的型別是字串時,它表示具有該標記名稱的DOM節點,並且props對應其屬性。這就是React將呈現的內容。例如:

{
  type: 'button',
  props: {
    className: 'button button-blue',
    children: {
      type: 'b',
      props: {
        children: 'OK!'
      }
    }
  }
}

element只是將以下HTML表示為普通物件的一種方法:

<button class
='button button-blue'>
<b> OK! </b> </button>

請注意元素如何巢狀。按照慣例,當我們想要建立一個元素樹時,我們將一個或多個子元素指定為其包含元素的children prop

重要的是,子元素和父元素都只是描述而不是實際的例項。

React元素很容易遍歷,不需要解析,當然它們比實際的DOM元素輕得多 - 它們只是物件!

Component Elements

我們知道,元素的型別(type)也可以是與React元件對應的函式或類:

{
  type: Button,
  props:
{ color: 'blue', children: 'OK!' } }

這是react的核心理念

描述元件的元素也是一個元素,就像描述DOM節點的元素一樣。它們可以巢狀並相互混合。

此功能可以將DangerButton元件定義為具有特定顏色屬性值的Button,而無需擔心Button是否呈現為DOM <button><div>或其他的標籤:

const DangerButton = ({ children }) => ({
  type: Button,
  props: {
    color: 'red',
    children: children
  }
});

也可以在一個元素樹中匹配dom或者component的元素。如下:

const DeleteAccount = () => ({
  type: 'div',
  props: {
    children: [{
      type: 'p',
      props: {
        children: 'Are you sure?'
      }
    }, {
      type: DangerButton,
      props: {
        children: 'Yep'
      }
    }, {
      type: Button,
      props: {
        color: 'blue',
        children: 'Cancel'
      }
   }]
});

或者可以用你jsx的形式:

const DeleteAccount = () => (
  <div>
    <p>Are you sure?</p>
    <DangerButton>Yep</DangerButton>
    <Button color='blue'>Cancel</Button>
  </div>
);

Components Encapsulate Element Trees

React看到一個具有函式(function)或類(class)型別的元素(element)時,它知道在給定相應的props的情況下向該元件詢問它呈現的元素。

比如他看到這麼一個元素:

{
  type: Button,
  props: {
    color: 'blue',
    children: 'OK!'
  }
}

React會詢問Button渲染什麼。然後Button會返回一個元素告訴他:

{
  type: 'button',
  props: {
    className: 'button button-blue',
    children: {
      type: 'b',
      props: {
        children: 'OK!'
      }
    }
  }
}

React將重複此過程,直到它知道頁面上每個元件的底層DOM元素都被標記。

React就像一個孩子,問你每個’X是Y’的’Y是什麼’,你向他們解釋,直到他們弄清楚世界上的每一件小事。

還記得上面的表單示例嗎?它可以用React編寫如下:

const Form = ({ isSubmitted, buttonText }) => {
  if (isSubmitted) {
    // Form submitted! Return a message element.
    return {
      type: Message,
      props: {
        text: 'Success!'
      }
    };
  }

  // Form is still visible! Return a button element.
  return {
    type: Button,
    props: {
      children: buttonText,
      color: 'blue'
    }
  };
};

對於React元件,props是輸入,元素樹是輸出。

返回的元素樹可以包含描述DOM節點的元素和描述其他元件的元素。這使得可以在不依賴於其內部DOM結構的情況下組成UI的獨立部分。

我們讓React建立,更新和銷燬例項。並且使用從元件返回的元素來描述它們,React負責管理例項。

Components Can Be Classes or Functions

在上面的例子中,Form, Message, Button都是元件。我們可以把它用function的方式展現,就像上面的那樣,也可以使用class繼承自React.Component。宣告元件的三種方式,可以像下面這樣:

// 1) As a function of props
const Button = ({ children, color }) => ({
  type: 'button',
  props: {
    className: 'button button-' + color,
    children: {
      type: 'b',
      props: {
        children: children
      }
    }
  }
});

// 2) Using the React.createClass() factory
const Button = React.createClass({
  render() {
    const { children, color } = this.props;
    return {
      type: 'button',
      props: {
        className: 'button button-' + color,
        children: {
          type: 'b',
          props: {
            children: children
          }
        }
      }
    };
  }
});

// 3) As an ES6 class descending from React.Component
class Button extends React.Component {
  render() {
    const { children, color } = this.props;
    return {
      type: 'button',
      props: {
        className: 'button button-' + color,
        children: {
          type: 'b',
          props: {
            children: children
          }
        }
      }
    };
  }
}

將元件定義為類時,它比功能元件更強大。它可以儲存一些本地狀態,並在建立或銷燬相應的DOM節點時執行自定義方法邏輯。

函式元件功能較弱但更簡單,並且只使用一個render方法。除非需要僅在class中提供的功能,否則建議使用function元件。

無論是函式還是類,從根本上說它們都是React的元件。他們將props作為輸入,並將元素作為輸出返回。

Top-Down Reconciliation

當我們呼叫下面程式碼時:

ReactDOM.render({
  type: Form,
  props: {
    isSubmitted: false,
    buttonText: 'OK!'
  }
}, document.getElementById('root'));

react會根據給定的props詢問Form元件返回什麼元素樹。

// React: 你告訴我這個
{
  type: Form,
  props: {
    isSubmitted: false,
    buttonText: 'OK!'
  }
}

// React: Form告訴我這個
{
  type: Button,
  props: {
    children: 'OK!',
    color: 'blue'
  }
}

// React: Button告訴我這個,此時預測已經結束。
{
  type: 'button',
  props: {
    className: 'button button-blue',
    children: {
      type: 'b',
      props: {
        children: 'OK!'
      }
    }
  }
}

這個是React和解過程中的一部分,並且這個是在呼叫ReactDOM.rendersetState時觸發的。

在和解結束後,React會知道DOM樹結果,並且像react-domreact-native這樣的渲染器應用,以最小的更改集去更新DOM節點(或者在React Native的情況下,特定於平臺的檢視) 。

這種漸進的精煉過程也是React應用程式易於優化的原因。如果元件樹的某些部分變得太大而React無法有效訪問,就可以告訴它跳過這個“精煉”並在相關props未更改的情況下區分樹的某些部分。如果它們是不可變的,那麼計算props是否已經改變是非常快的,因此Reactimmutability可以很好地協同工作,並且可以用最小的努力提供很好的優化。

你可能已經注意到,此部落格條目對元件和元素進行了大量討論,而不是例項。事實上,例項在React中的重要性遠遠低於大多數面向物件的UI框架。

只有宣告為類的元件才有例項,而且你永遠不會直接建立它們:React會為你做這件事。雖然存在父元件例項訪問子元件例項的機制,但它們僅用於命令性操作(例如將焦點設定在欄位上),並且通常應該避免。

React負責為每個類元件建立一個例項,因此您可以使用方法和本地狀態以面向物件的方式編寫元件,但除此之外,例項在React的程式設計模型中並不是非常重要,並且由React本身管理。

總結

元素是一個普通物件,用於描述您希望在DOM節點或其他元件方面在螢幕上顯示的內容。元素可以在其道具中包含其他元素。建立React元素很簡單。一旦建立了一個元素,它就永遠不會發生改變。

元件可以用幾種不同的宣告方式。它可以是一個帶有render方法的類。或者,在簡單(你可以認為是沒有狀態)的情況下,可以將其定義為函式。在任何一種情況下,它都將props作為輸入,並返回一個元素樹作為輸出。

當一個元件接收一些props作為輸入時,這是因為一個特定的父元件返回了一個元素及其型別和這些props。這就是人們說propsReact中以一種方式流動的原因:從父母到孩子。

在編寫的元件類中,this就是指的例項。它對於儲存本地狀態和對生命週期事件做出反應非常有用。

功能元件根本沒有例項。類元件有例項,但您永遠不需要直接建立元件例項–React負責這一點。

最後,要建立元素,請使用React.createElementJSX元素工廠助手。不要在真實程式碼中將元素寫為普通物件 - 只要知道它們是引擎蓋下的普通物件。

擴充套件閱讀

本文doc地址
原文地址