React 學習筆記: 深刻 JSX

React.createElement

本質上講,JSX 只是 React.createElement(component, props, ...children) 的語法糖(JSX 在線Babel編譯器)。所以,在用到 JSX 時,即便並無用到React,做用域中也必須包含 React 庫:import React from 'react'。例如:node

  1. 寫函數組件時,react

    function Welcome(props) {
      return <h1>Hello, {props.name}</h1>;
    }
  2. 配置文件 Object 中包含 JSX:數組

    {
      ...
      render: (data) => <div>{data}</div>
      ...
    }

爲何 JSX 中的組件名要以大寫字母開頭?

小寫字母開頭: 內置組件,HTML 元素,例如 <div><span>,會編譯成 React.createElement('div')
大寫字母開頭:自定義組件或 JS 文件中導入的組件,例如 <Foo /><MyComponents.DatePicker />,會編譯成 React.createElement(Foo)
例外:在 JSX 中使用點語法(Dot Notation)表示一個 React 組件 <obj.component /> 會編譯成 React.createElement(obj.component)
解釋:JSX 語法依賴babel進行解析。在 @babel/plugin-transform-react-jsx 中,babel

const visitor = helper({
  pre(state) {
    const tagName = state.tagName;
    const args = state.args;
    if (t.react.isCompatTag(tagName)) {
      args.push(t.stringLiteral(tagName));
    } else {
      args.push(state.tagExpr);
    }
  },

  post(state, pass) {
    state.callee = pass.get("jsxIdentifier")();
  },

  throwIfNamespace: THROW_IF_NAMESPACE,
});
function isCompatTag(tagName) {
  return !!tagName && /^[a-z]/.test(tagName);
}

即小寫字母開頭的 tagName 直接轉爲 string 字符串;ide

// returns a closure that returns an identifier or memberExpression node
// based on the given id
const createIdentifierParser = (id: string) => () => {
  return id
    .split(".")
    .map(name => t.identifier(name))
    .reduce((object, property) => t.memberExpression(object, property));
};

即在 JSX 中使用點語法(Dot Notation)時,無論是大寫仍是小寫,最終都會解析成對象和屬性,而不是字符串,也因此雖然 C[p] 和 C.p 同樣,可是 JSX 中 <c.p /> 能夠解析而 <c[p] /> 不行。函數

import React from 'react';
import { PhotoStory, VideoStory } from './stories';

const components = {
  photo: PhotoStory,
  video: VideoStory
};

function Story(props) {
  // 錯誤!JSX 類型不能是表達式
  return <components[props.storyType] story={props.story} />;

  // 正確!JSX 類型能夠是一個以大寫字母開頭的變量.
  const SpecificStory = components[props.storyType];
  return <SpecificStory story={props.story} />;
}

JSX 是表達式且能夠嵌入表達式

JSX 是表達式,編譯後就變成常規的 Javascript 對象,因此能夠post

  • 給變量賦值:const button = <button>{name}</button>
  • 當作參數接收this

    getFieldDecorator('price', {
      initialValue: { number: 0, currency: 'rmb' },
      rules: [{ validator: this.checkPrice }],
    })(<PriceInput />)
  • 做爲函數的返回值: render: () => <Foo />

JSX props 能夠用 Javascript 表達式或字符串字面量。props.children(標籤中的內容) 是個特殊的 props。
在 JavaScript 中,if 語句和 for 循環不是表達式,所以不能在 JSX 中直接使用。spa

  • JavaScript 邏輯 && 運算符替代 if
  • 條件操做符 condition ? true : false 替代 if-else
  • map() 函數替代 for 循環

falsy 值渲染

falsy 是在 Boolean 上下文中已認定可轉換爲‘假’的值。code

if (false)
if (null)
if (undefined)
if (0)
if (NaN)
if ('')
if ("")
if (document.all)

false,null,undefined,和 true 是有效的children,可是不會被渲染;
falsy 值例如 0,則會被渲染,例如:

// props.messages 是空數組時,props.messages.length 爲 0 會被渲染出來。
<div>
  {props.messages.length &&
    <MessageList messages={props.messages} />
  }
</div>

應該改爲:

<div>
  {props.messages.length > 0 &&
    <MessageList messages={props.messages} />
  }
</div>
相關文章
相關標籤/搜索