React学习笔记:JSX

React:JSX

一、JSX优点:

  • 更加熟悉
  • 更加语义化
  • 更加直观
  • 抽象化
  • 关注点分离

二、定义组件

var Divider = React.createClass({
    render: function () {
        return (
            <div className="divider">
                <h2>定义组件Demo</h2>
            </div>
        );
    }
});

三、动态值

动态值包含在 {} 之中,这其中也自动包括了一个Javascript上下文,因此可以直接在里面调用 this。其中相当于执行普通的JavaScript代码,可以放进去变量或者函数等。

1. 调用外置变量与函数

var text = "定义组件Demo";
var getText = function () {
    return "函数";
};
var Divider = React.createClass({
    render: function () {
        return (
            <div className="divider">
                <h2>{text}</h2>
                <h2>{getText()}</h2>
            </div>
        );
    }
});

2. 调用组件内变量与函数

var Divider = React.createClass({
    text: "定义组件Demo",
    getText: function () {
        return "函数";
    },
    render: function () {
        return (
            <div className="divider">
                <h2>{this.getText()}</h2>
                <h2>{this.text}</h2>
            </div>
        );
    }
});

3. 数组

直接调用数组,输出的是[].join('')后的结果。

// 精简代码
var text = ['hello', 'world'];
<h2>{text}</h2>
// <h2>helloworld</h2>

对于复杂的表达式,可以通过函数求值来完成。

四、子节点

在React中,所有的子节点都保存在this.props.children中。

注意:在当前组件内,你直接输出this.props.children是得不到任何信息的,会返回undefined,因为该属性是组件的拥有者传递过来的信息,所以,只能在渲染组件的时候进行输出。

比如:

var Divider = React.createClass({
   // 调用组件的时候,传入了自节点,在此输出
   componentWillMount: function () {
      console.log(this.props);
      // Object {children: "hello"}
   },
   render: function () {
     return (
       <div className="divider">
         <h2>{this.props.children}</h2>
       </div>
     )
   }
});
var newDivider = <Divider>hello</Divider>;
ReactDOM.render(newDivider, document.getElementById('container'));

五、JSX与HTML的区别

1. 属性

html中可以用内联的方式为元素添加属性,例如:

<div class="container" id="container">hello world!</div>

在JSX中也可以给类HTML元素类HTML属性,除此之外,还可以给添加的输定设置动态的值或者变量,即前面提到的{}

var queryId = "container";
<h2 id={queryId}></h2>

特殊属性

注意:大多数的HTML元素的属性都可以直接用到JSX中,有些是不可以直接拿来用的,比如关键字:classfor等,需要用classNamehtmlFor来代替。

2. 条件判断

简单的JavaScript语法都可以使用,最常用的基本为以下四个:

  • 使用三目运算符
  • 设置一个变量并在属性中引用它
  • 将逻辑转化到函数中
  • 使用&&运算符

如下示例:

// 三目运算符
<div className={this.state.isDone?'i-open':'i-close'}>hello wolrd</div>

// 使用变量
getIsDone: function () {
    return this.state.isDone ? ' i-open' : ' i-close';
},
render: function () {
    var isDone = this.getIsDone();
    return (
        <div className={isDone}>hello wolrd</div>
    )
}

// 或者直接调用函数
getIsDone: function () {
    return this.state.isDone ? ' i-open' : ' i-close';
},
render: function () {
    return (
        <div className={this.getIsDone()}>hello wolrd</div>
    )
}

// 使用逻辑与&&
<div className={this.state.isDone && this.getIsDone()}>hello world</div>

对于nullfalse值React不会输出任何内容,通过逻辑与,第一个值为true时,第二个语句便会执行。

也可以判断显示那个组件:

var content = <Container>{window.isLogin? <Nav /> : <Login /> };

3. 非DOM属性

以下特殊属性只有在JSX中有:

  • 键:key
  • 引用:ref
  • 设置原始的HTML:dangerouslySetInnerHTML

key是唯一标识符。

ref是reference的缩写,可以直接在JSX中指定:

<div className="container" ref="myContainer">...</div>

这样,就可以在组件的refs属性中获取该DOM(并不是真实的)。

componentDidMount: function (){
    console.log( this.refs.aaa );
    // Object {aaa: div.divider}
},
render: function () {
    return (
        <div className="divider" ref="aaa">...</div>
    )
}

该方式获取的是React创建DOM的描述(难以理解。。。),如果要获取真正的DOM节点,可继续调用getDOMNode方法:

this.refs.aaa.getDOMNode();

dangerouslySetInnerHTML,暂时没有进行深入学习。

4. 事件

在React中,所有的事件都被规范化并统一以驼峰形式命名。这些事件被自动的绑定上了组件所有方法的作用域,可以直接调用this即可。

比如:

click => onClick
submit => onSubmit
change => onChange
...

使用例子:

handleClick: function () {
    alert("hello");
},
render: function () {
    return (
        <button onClick={this.handleClick}>点击我</button>
    )
}

5. 注释

基本上来说,可以在任何地方进行注释,注释有两种,单行与多行,与普通js注释相同。毕竟JSX本质上也是JavaScript。

<div className="container" /* note here */><div>
<div
    /*
        note here
    */
    className="email"></div>

6. 样式

对于内联样式,使用方式和普通的JSX语法相同,不过注意的时,所有的样式都是驼峰命名写法:

var style = {
    backgroundColor: "red",
    marginTop: "20px"
};
<h2 style={style}></h2>

上面的写法是比较清楚的,也可以直接写到行内:

<h2 style={{backgroundColor:"red", marginTop:"20px"}}></h2>

两种写法是相同的,只不过第二种看起来怪怪的(两个大括号)。

六、简写

有时候我们写一个组件有许多的小组件,那么一直写React.createClass会比较麻烦,此时可以定义一个简写的规则,比如:

var R = React.createClass;
var E = React.createElement;
var Divider = R({
    render: function () {
        return (
            E("div", null, 'hello')
        )
    }
});

因为现在的React版本已经比较固定,只有React.createClass以及React.createElement调用即可,这种简写方式已经不那么重要,在0.11版本的时候,当时创建元素的时候是这样的:

React.DOM.div // 创建div
React.DOM.h2 // 创建h2
...

所以,那个时候的简写比较有价值:

var div = React.DOM.div
var h2 = React.DOM.h2
...

七、JSX转换

有一点需要注意:JSX只有一个语法糖,其会被编译成标准的JavaScript代码。

  • 类XML 语法转换成纯JavaScript
  • XML元素、属性和节点转换成React.createElement的参数

比如:

// 输入(JSX)
var Nav;
var app = <Nav color="blue" />;

// 输出(JS)
var app = React.createElement(Nav, {color: 'blue'});

子节点的转换

// 输入:JSX
var Nav, Tab;
var app = <Nav color="blue"><Profile>click</Profile></Nav>;

// 转换后:JS
var app = React.createElement(
    Nav,
    {color:"blue"},
    React.createElement(Profile, null, "click") );

八、JSX陷阱

1. HTML实体

HTML实体可以直接插入到JSX的文本中:

render: function () {
    return (
        <h2>hello  ©</h2>
    )
}

为了防止XSS攻击,React默认会对所有的字符串进行转义,防止XSS攻击:

render: function () {
    return (
        <h2>{'hello  © world'}</h2>
    )
}

这样的话,React会直接把这些符号当做字符串输出到页面上。有多种绕过的方法,最简单的就是使用Unicode字符,但必须要确保文件编码和网页编码同时是utf-8

<div>{'hello © world'}</div>

另外一种做法就是使用Unicode对应的编号。

2. 自定义HTML属性

使用自定义属性,必须加data-前缀,要不然React不会识别,那么就不会显示。

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

但是对于自定义组件,可以添加自定义属性:

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

这些属性通过this.props获取到。

以 aria- 开头的 [网络无障碍] 属性可以正常使用。

<div aria-hidden={true} />

九、拓展

1. 不要修改props

不建议定义好组件后,在修改props,这是反模式,因为React不能帮你检测属性类型,出错后得不到正确的提示,可能导致意想不到的结果。所以,尽量不要修改props。

// 该代码不建议使用:
var Comment = <Comment />;
Comment.props.name = "a";
Comment.props.title = "aa";

2. 延展属性

JSX的新特性--延展属性。

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

上面的 ...便是延展操作符。上面的操作和下面的是一个意思:

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

延展属性会把传入对象的属性复制到组件内。

发表评论

电子邮件地址不会被公开。 必填项已用*标注