react學習系列之深刻jsx

JSX是一種javascript語法擴展(也就是語法糖),相似於XML,通常用babel編譯成javascriptjavascript

Why JSX?

React裏可使用原生的javascript,可是React官方推薦使用JSX,使用JSX,組件的結構和組件之間的關係看上去更加清晰。
前端界面的最基本功能在於展示數據,爲此大多數框架都使用了模板引擎
模板能夠直觀的定義UI來展示Model中的數據,你沒必要手動的去拼出一個很長的HTML字符串,幾乎每種框架都有本身的模板引擎。傳統MVC框架強調界面展現邏輯和業務邏輯的分離,所以爲了應對複雜的展現邏輯需求,這些模板引擎幾乎都不可避免的須要發展成一門獨立的語言,如上面代碼所示,每一個框架都有本身的模板語言語法。而這無疑增長了框架的門檻和複雜度。
React直接放棄了模板而發明了JSX。看上去很像模板語言,但其本質是經過代碼來構建界面,這使得咱們再也不須要掌握一門新的語言就能夠直觀的去定義用戶界面:掌握了javascript就已經掌握了JSX
JSX完美利用了javascript自帶的語法和特性,咱們只要記住HTML只是代碼建立DOM的一種語法形式,就很容易理解JSX。而這種使用代碼構建界面的方式,徹底消除了業務邏輯和界面元素之間的隔閡,讓代碼更加直觀和易於維護。html

Transform

var Nav, Profile;
// Input (JSX):
var app = <Nav color="blue"><Profile>click</Profile></Nav>;
// Output (JS):
var app = React.createElement(
  Nav,
  {color:"blue"},
  React.createElement(Profile, null, "click")
);

也就是說,咱們寫一個XML標籤,實質上就是在調用 React.createElement 這個方法,並返回一個 ReactElement 對象。
擴展: React.createElement用法前端

ReactElement createElement(
  string/ReactClass type,
  [object props],
  [children ...]
)

經過上面的代碼能夠看出JSX的優點,XML有着開閉標籤,在構建複雜的樹形結構時,比函數調用和對象字面量更易讀java

HTML Tags vs. React Components

React.render方法能夠渲染HTML結構,也能夠渲染React組件。
渲染HTML標籤,聲明變量採用首字母小寫segmentfault

var myDivElement = <div className="foo" />;
ReactDOM.render(myDivElement, document.getElementById('example'));

渲染React組件,聲明變量採用首字母大寫數組

var MyComponent = React.createClass({/*...*/});
var myElement = <MyComponent someProperty={true} />;
ReactDOM.render(myElement, document.getElementById('example'));

語法

JSX的基本語法規則:遇到 HTML 標籤(以 < 開頭),就用 HTML 規則解析;遇到代碼塊(以 { 開頭),就用 JavaScript 規則解析。JSX容許直接在模板插入 JavaScript 變量。若是這個變量是一個數組,則會展開這個數組的全部成員:安全

var arr = [
  <h1>Hello world!</h1>,
  <h2>React is awesome</h2>,
];
React.render(
  <div>{arr}</div>,
  document.getElementById('example')
);

Attribute Expressions

// Input (JSX):
var person = <Person name={window.isLoggedIn ? window.name : ''} />;
// Output (JS):
var person = React.createElement(
  Person,
  {name: window.isLoggedIn ? window.name : ''}
);

Child Expressions

// Input (JSX):
var content = <Container>{window.isLoggedIn ? <Nav /> : <Login />}</Container>;
// Output (JS):
var content = React.createElement(
  Container,
  null,
  window.isLoggedIn ? React.createElement(Nav) : React.createElement(Login)
);

Boolean Attributes

// These two are equivalent in JSX for disabling a button
<input type="button" disabled />;
<input type="button" disabled={true} />;

// And these two are equivalent in JSX for not disabling a button
<input type="button" />;
<input type="button" disabled={false} />;

註釋

JSX 裏添加註釋很容易;它們只是 JS 表達式而已。你只須要在一個標籤的子節點內(非最外層)當心地用 {} 包圍要註釋的部分。babel

var content = (
  <Nav>
    {/* 通常註釋, 用 {} 包圍 */}
    <Person
      /* 多
         行
         註釋 */
      name={window.isLoggedIn ? window.name : ''} // 行尾註釋
    />
  </Nav>
);

因爲JSX只是一種語法,所以JavaScript的關鍵字class, for等也不能出如今XML中,而要使用className, htmlFor代替,這和原生DOM在JavaScript中的建立也是一致的。網絡

Spread Attributes

若是你事先知道組件須要的所有 Props(屬性),JSX 很容易地這樣寫:app

var component = <Component foo={x} bar={y} />;

若是你不知道要設置哪些 Props,那麼如今最好不要設置它:

var component = <Component />;
  component.props.foo = x; // bad
  component.props.bar = y; // also bad

這樣是反模式,由於 React 不能幫你檢查屬性類型(propTypes)。這樣即便你的 屬性類型有錯誤也不能獲得清晰的錯誤提示。

Props 應該被看成禁止修改的。修改 props 對象可能會致使預料以外的結果,因此最好不要去修改 props 對象。
能夠用展開屬性來寫

var props = {};
  props.foo = x;
  props.bar = y;
  var component = <Component {...props} />;

傳入對象的屬性會被複制到組件內。

它能被屢次使用,也能夠和其它屬性一塊兒用。注意順序很重要,後面的會覆蓋掉前面的。

var props = { foo: 'default' };
  var component = <Component {...props} foo={'override'} />;
  console.log(component.props.foo); // 'override'

JSX 陷阱

JSX 與 HTML 很是類似,可是有些關鍵區別要注意。

內聯樣式

在React中寫行內樣式時,要這樣寫,不能採用引號的書寫方式

React.render(
    <div style={{color:'red'}}>
        xxxxx
    </div>,
    document.body
);

HTML 實體

React默認會進行HTML的轉義,避免XSS攻擊
有多種繞過的方法。最簡單的是直接用 Unicode 字符。這時要確保文件是 UTF-8 編碼且網頁也指定爲 UTF-8 編碼。

<div>{'First · Second'}</div>

安全的作法是先找到 實體的 Unicode 編號 ,而後在 JavaScript 字符串裏使用。

<div>{'First \u00b7 Second'}</div>
 <div>{'First ' + String.fromCharCode(183) + ' Second'}</div>

還能夠直接使用原生的HTML,但能夠看出不推薦這種作法

<div dangerouslySetInnerHTML={{'{{'}}__html: 'First &middot; Second'}} />

自定義 HTML 屬性

若是往原生 HTML 元素裏傳入 HTML 規範裏不存在的屬性,React 不會顯示它們。若是須要使用自定義屬性,要加 data- 前綴。

<div data-custom-attribute="foo" />

以 aria- 開頭的 [網絡無障礙] 屬性能夠正常使用。

<div aria-hidden={true} />

TIPS

三元運算符代替IF...ELSE

在JSX中是不能夠直接在{}中加入if-else的,可使用下面這種三元表達式:

React.render(<div id={condition ? 'msg' : ''}>Hello World!</div>, mountNode);

在三元運算符知足不了的時候,React建議的方式是在JS代碼中使用if表達式

var loginButton;
if (loggedIn) {
  loginButton = <LogoutButton />;
} else {
  loginButton = <LoginButton />;
}

return (
  <nav>
    <Home />
    {loginButton}
  </nav>
);

Switch-Case

return (
  <section>
    <h1>Color</h1>
    <h3>Name</h3>
    <p>{this.state.color || "white"}</p>
    <h3>Hex</h3>
    <p>
      {(() => {
        switch (this.state.color) {
          case "red":   return "#FF0000";
          case "green": return "#00FF00";
          case "blue":  return "#0000FF";
          default:      return "#FFFFFF";
        }
      })()}
    </p>
  </section>
);

False in JSX

ReactDOM.render(<div id={false} />, mountNode);

渲染出 id="false"

ReactDOM.render(<input value={false} />, mountNode);

渲染出字符串"false"做爲input的value

ReactDOM.render(<div>{false}</div>, mountNode);

渲染出無子元素

命名空間式組件

用法以下
命名空間式組件容許你使用一個父組件,而其餘的子組件是他的屬性

var Form = MyFormComponent;
 
var App = (
  <Form>
    <Form.Row>
      <Form.Label />
      <Form.Input />
    </Form.Row>
  </Form>
);

var MyFormComponent = React.createClass({ ... });
MyFormComponent.Row = React.createClass({ ... });
MyFormComponent.Label = React.createClass({ ... });
MyFormComponent.Input = React.createClass({ ... });

注意點以下: React.js的命名空間的組件
只在0.11及以上版本可用

相關文章
相關標籤/搜索