005@关于JSX语法.md

005@关于JSX语法

转(有所更改):React入门:关于JSX语法
可以参考的资料:
React.js学习笔记之JSX解读

JSX=JavaScriptXML。 JSX是React的核心组成部分,它使用XML标记的方式去直接声明界面,界面组件之间可以互相嵌套。

SX可以看作JavaScript的拓展,看起来有点像XML。使用React,可以进行JSX语法到JavaScript的转换。

    //使用JSX
    React.render(
        <div>
            <div>
                <div>content</div>
            </div>
        </div>,
        document.getElementById('example')
    );
     
    //不使用JSX
    React.render(
        React.createElement('div', null,
            React.createElement('div', null,
                React.createElement('div', null, 'content')
            )
        ),
        document.getElementById('example')
    );

那么也就是说,我们写一个XML标签,实质上就是在调用React.createElement这个方法,并返回一个ReactElement对象。

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

这个方法的第一个参数可以是一个字符串,表示是一个HTML标准内的元素,或者是一个ReactClass类型的对象,表示我们之前封装好的自定义组件。第二个参数是一个对象,或者说是字典也可以,它保存了这个元素的所有固有属性(即传入后基本不会改变的值)。从第三个参数开始,之后的参数都被认作是元素的子元素。

JSX语法

SX本身就和XML语法类似,可以定义属性以及子元素。唯一特殊的是可以用大括号来加入JavaScript表达式,例如

var HelloMessage = React.createClass({
  render: function() {
    return <div>Hello {this.props.name}</div>;
  }
});
ReactDOM.render(<HelloMessage name="xiaowang" />, mountNode);

一、元素名

自定义出的组件标签名,React 的 JSX 里约定分别使用首字母大、小写来区分本地组件的类和 HTML 标签。render渲染时,会把大写的组件名定义为自定义组件,把小写的组件名定义为HTML自带的标签名进行渲染。

var HelloMessage =

JSX的标签与函数名都是使用的驼峰命名。
htmlFor和className

for和class为js的保留字,在书写for与class时需要修改为htmlFor何className,注意都是使用的驼峰命名。
自闭合标签

在 JSX 中, <MyComponent /> 是合法的,而 <MyComponent> 就不合法。 所有的标签都必须闭合,可以是自闭和的形式,也可以是常规的闭合。

注意:所有 React component 都可以采用自闭和的形式,包括div等

二、子节点

组件与组件之间就像标签与标签之间可以有嵌套关系,与HTML不同的是可以在子节点中使用求值表达式。目前, 一个 component 的 render,只能返回一个节点。如果你需要返回一堆 div , 那你必须将你的组件用 一个div 或 span 或任何其他的组件包裹。

** 切记,JSX 会被编译成常规的 JS; 因此返回两个函数也就没什么意义了,同样地,千万不要在三元操作符中放入超过一个子节点。**

节点属性:

使用标签的时候指定属性和属性值传入标签内部,使标签内部可以使用属性值。
注意:

如果往原生 HTML 元素里传入 HTML 规范里不存在的属性,React 不会显示它们。如果需要使用自定义属性,要加 data- 前缀。

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

然而任意属性支持自定义元素

    <x-my-component custom-attribute="foo" />

三、求值表达式

要使用 JavaScript 表达式作为属性值,只需把这个表达式用一对大括号 ( { } ) 包起来,不要用引号 ( " " )。求值表达式本身与JSX没有多大关系,是JS中的特性。它是会返回值的表达式,与语句有本质上的不同,在编写JSX时,在 { } 中不能使用语句(if语句、for语句等等)。我们不能直接使用语句,但可以把语句包裹在函数求值表达式中运用。建议把函数表达式独立出来,在 { } 调用。

你没法在JSX中使用 if-else 语句,因为 JSX 只是函数调用和对象创建的语法糖。在 { } 中使用,是不合法的JS代码,不过可以采用三元操作表达式

var HelloMessage = React.createClass({
  render: function() {
    return <div>Hello {this.props.name ? this.props.name : "World"}</div>;
  }
});
ReactDOM.render(<HelloMessage name="xiaowang" />, document.body);

可以使用比较运算符“ || ”来书写,如果左边的值为真,则直接返回左边的值,否则返回右边的值,与if的效果相同。

var HelloMessage = React.createClass({ 
  render: function() {
      return <div>Hello {this.props.name || "World"}</div>;
  }
});
ReactDOM.render(<HelloMessage name="xiaowang" />, document.body);

也可以使用变量来书写

var HelloMessage = React.createClass({
  getName : function() {
      if (this.props.name)
          return this.props.name
      else
          return "world"
  } 
  render: function() {
      var name = this.getName();
      return <div>Hello {name}</div>;
  }
});
ReactDOM.render(<HelloMessage name="xiaowang" />, document.body);

其中可以把变量去掉,直接在 { } 中调用函数

  render: function() {
      return <div>Hello {this.getName()}</div>;
  }

函数表达式

( )有强制运算的作用

var HelloMessage = React.createClass({ 
  render: function() {
      return <div>Hello {
          (function(obj){
              if(obj.props.name)
                  return obj.props.name
              else
                  return "World"
              }(this))
      }</div>;
  }
});
ReactDOM.render(<HelloMessage name="xiaowang" />, document.body);

外括号“ )”放在外面和里面都可以执行。唯一的区别是括号执行完毕拿到的是函数的引用,然后再调用;括号放在外面的时候拿到的事返回值。需传入(this)。

四、注释

JSX 里添加注释很容易;它们只是 JS 表达式而已。你只需要在一个标签的子节点内(非最外层)小心地用 { } 包围要注释的部分。

var content = (
  <Nav>
    {/* 一般注释, 用 {} 包围 */}
    <Person
      /* 多
         行
         注释 */
      name={window.isLoggedIn ? window.name : ''} // 行尾注释
    />
  </Nav>
);

转化

React JSX将类似XML的语法转化到原生的JavaScript,元素的标签、属性和子元素都会被当作参数传给React.createElement方法:

#JSX
var Nav;
var app = <Nav color="blue" />;
     
#native JS
var Nav;
var app = React.createElement(Nav, {color:"blue"});

JSX转化器

要把带有JSX语法的代码转化为纯Javascript代码,有多种方式,对于内联与HTML中的代码或者是未经过转化的外部文件,在script标签中要加上type="text/jsx",并引入JSXTransformer.js文件即可,不过这种方式并不建议在生产环境使用,建议的方法是在代码上线前就将代码转换好,可以使用npm全局安装react-tools:

npm install -g react-tools

并使用命令行工具转化即可(具体用法可以参考jsx -h):

jsx src/ build/

HTML 标签 vs. React 组件

React.render方法可以渲染HTML结构,也可以渲染React组件。
渲染HTML标签,声明变量采用首字母小写

    var myDivElement = <div className="foo" />;
    React.render(myDivElement, document.body);

渲染React组件,声明变量采用首字母大写

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

React 的 JSX 使用大写和小写字母来区分本地的组件类和 HTML 标签.

不过需要注意的是class和for这两个属性,JSX语法最终是要被转换为纯Javascript的,所以要和在Javascript DOM中一样,用className和htmlFor。

    //使用JSX
    React.render(
        <label className="xxx" htmlFor="input">content</label>,
        document.getElementById('example')
    );
     
    //不使用JSX
    React.render(
        React.createElement('label', {className: 'xxx', htmlFor: 'input'}, 'content'),
        document.getElementById('example')
    );

还有一点是,在创建HTML标准内的元素时,JSX转化器会丢弃那些非标准的属性,如果一定要添加自定义属性,那么需要在这些自定义属性之前添加data-前缀。

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

命名空间式组件

比如开发组件的时候,一个组件有多个子组件,你希望这些子组件可以作为其父组件的属性,那么可以像这样用:

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

这样你只需将子组件的ReactClass作为其父组件的属性:

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

而创建子元素可以直接交给JSX转化器:

    var App = (
        React.createElement(Form, null,
            React.createElement(Form.Row, null,
                React.createElement(Form.Label, null),
                React.createElement(Form.Input, null)
            )
        )
    );

Javascript表达式

在JSX语法中写Javascript表达式只需要用{}即可,比如下面这个使用三目运算符的例子:

JSX是HTML和JavaScript混写的语法,当遇到<,JSX就当HTML解析,遇到{就当JavaScript解析。

    // 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)
    );

属性表达式

    React.render(
        <div className={2 > 1 ? 'class-a' : 'class-b'}>content</div>,
        document.body
    );

子表达式

    var Nav = React.createClass({
        render: function () {
            return <div>nav</div>
        }
    });
     
    React.render(
        <div>
            {2 > 1 ? <Nav/> : <div>div</div>}
        </div>,
        document.body
    );

不过要注意的是,JSX语法只是语法糖,它的背后是调用ReactElement的构造方法React.createElement的,所以类似这样的写法是不可以的:

    // This JSX:
    <div id={if (condition) { 'msg' }}>Hello World!</div>
     
    // Is transformed to this JS:
    React.createElement("div", {id: if (condition) { 'msg' }}, "Hello World!");

可以从转化后的Javascript代码中看出明显的语法错误,所以要不用三目运算符,要不就这样写:

    if (condition) <div id='msg'>Hello World!</div>
    else <div>Hello World!</div>

传播属性(Spread Attributes)

如果提前就知道了组件的属性的话,写起来很容易。例如component组件有两个动态的属性foo和bar:

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

而实际上,有些属性可能是后续添加的,我们没办法一开始就确定,我们可能会写出下面不好的代码:

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

这样写是错误的,因为我们手动直接添加的属性React后续没办法检查到属性类型错误,也就是说,当我们手动添加的属性发生类型错误时,在控制台是看不到错误信息的。

在React的设定中,初始化完props后,props是不可变的。改变props会引起无法想象的后果。

延伸属性

为了解决这个问题,React引入了属性延伸

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

这样就相当于:

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

当需要拓展我们的属性的时候,定义个一个属性对象,并通过{…props}的方式引入,在JSX中,可以使用...运算符,表示将一个对象的键值对与ReactElement的props属性合并,这个...运算符的实现类似于ES6 Array中的...运算符的特性。,React会帮我们拷贝到组件的props属性中。重要的是—这个过程是由React操控的,不是手动添赋值的属性。

它也可以和普通的XML属性混合使用,需要同名属性,后者将覆盖前者:

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

JSX 陷阱

style属性

在React中写行内样式时,要这样写,不能采用引号的书写方式

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

HTML转义

比如我们有一些内容是用户输入的富文本,从后台取到数据后展示在页面上,希望展示相应的样式

    var content='<strong>content</strong>';
     
    React.render(
        <div>{content}</div>,
        document.body
    );

结果页面直接输出内容了:

<strong>content</strong>

React默认会进行HTML的转义,避免XSS攻击,如果要不转义,可以这么写:

    var content='<strong>content</strong>';    
     
    React.render(
        <div dangerouslySetInnerHTML={{__html: content}}></div>,
        document.body
    );
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,686评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,668评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,160评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,736评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,847评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,043评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,129评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,872评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,318评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,645评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,777评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,861评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,589评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,687评论 2 351

推荐阅读更多精彩内容