react原始碼淺析(三):ReactElementValidator

hy醬發表於2019-03-01

react原始碼淺析(三):ReactElementValidator

react相關庫原始碼淺析react ts3 專案

  1. react遇到React.Fragment標籤,先驗證器檢測是否符合規範,再呼叫createElement建立reactElement。
  2. React.Fragment允許傳入的屬性有key,children,不能傳入ref以及其他屬性,因為React.Fragment最終不會渲染成一個真實DOM,所以ref引用到的是null,因此不能傳入ref作為屬性。

部分函式列表

getDeclarationErrorAddendum ------ 返回字串,內容為:檢查ReactCurrentOwner.current.type上的render方法
getSourceInfoErrorAddendum ------- 返回字串,內容為:檢查某個檔案下的某一行程式碼
getCurrentComponentErrorInfo ----- 錯誤提示,在ReactCurrentOwner.current不存在的時候,提示檢查parentType上的render
validateExplicitKey -------------- 對傳入的元件是否具有key進行錯誤處理
validateChildKeys ---------------- 對傳入的node中的每個element判斷是否存在key
validatePropTypes ---------------- 檢查propTypes的否大小寫正確,類元件或者函式元件設定預設prop只能用defaultProps,getDefaultProps只能用於React.createClass中
複製程式碼

validateFragmentProps

React.Fragment 也是通過createElement建立的。 React.Fragment 只能有key和children作為其屬性。 React.Fragment 特別注意不能傳入ref作為其屬性,因為React.Fragment不會渲染成一個真實的DOM,自然不會允許有ref。

<React.Fragment key111="Fragment 只能有key和children作為其屬性"

children111="Fragment 只能有key和children作為其屬性"
ref={{"some":"Fragment 也不能使用ref獲取引用"}}
key="允許的"
children="允許的,貌似沒什麼用,真實的children就是React.Fragment包裹的內容"
    >
    Some text.
<h2>A heading</h2>
</React.Fragment>
複製程式碼

createElementWithValidation

  1. 先檢查傳入的type是否是合法的element型別,見isValidElementType,如果不是丟擲錯誤
  2. 如果是則將type, props, children等引數傳入createElement生成對應的react元素
  3. 然後呼叫validateChildKeys對引數children的每個element判斷是否存在key
  4. 接著,如果type型別是REACT_FRAGMENT_TYPE,呼叫validateFragmentProps檢查Fragment上的屬性(這裡函式名為props不妥,key與ref不算是props中的,attributes比較好),其他type型別的元素的props的規則一致。
  5. 最後如果驗證成功,返回建立的element。

createFactoryWithValidation

工廠函式,對createElementWithValidation的封裝,返回一個函式,該函式用於建立一個element

export function createFactoryWithValidation(type) {
  const validatedFactory = createElementWithValidation.bind(null, type);
  validatedFactory.type = type;
  return validatedFactory;
}
複製程式碼

cloneElementWithValidation

返回一個REACT_ELEMENT_TYPE型別的元素,其type屬性值為傳入的element,

export function cloneElementWithValidation(element, props, children) {
  const newElement = cloneElement.apply(this, arguments);
  for (let i = 2; i < arguments.length; i++) {
    validateChildKeys(arguments[i], newElement.type);
  }
  //newElement為REACT_ELEMENT_TYPE型別,所以不許要判斷是否是REACT_FRAGMENT_TYPE型別
  validatePropTypes(newElement);
  return newElement;
}
複製程式碼

這個函式在開發環境下會作為React.cloneElement方法。而在生產環境下ReactElement.js中的cloneElement會作為React.cloneElement方法。

例1:children作為屬性

ReactDOM.render(
    <React.Fragment children={["child","child","child"]}/>,
    document.getElementById('app')
);
複製程式碼

例2:

let ReactFragment1 = React.cloneElement(<React.Fragment children={["child","child","child"]}/>,{xxx:"這會被新增到新元件的props上"})
console.log("ReactFragment1",ReactFragment1)
console.log("ReactFragment1",React.Fragment)

ReactDOM.render(
    ReactFragment1,
    document.getElementById('app')
);
複製程式碼

相關文章