react

一、ReactDom.render()方法是react的最基本的方法,用于将模板转为HTML语言,并插入到指定的DOM节点里。

ReactDom.render(
    <h1>Hello,world!</h1>,
    document.getElementById('example')   
)

二、JSX语法

上一节代码中,html标签直接写在javascript语言中,不加任何引号,这就是JSX语法,他允许HTML和javascript的混写

var names = ['Alice', 'Emily', 'Kate'];
ReactDOM.render(
  <div>
    {
      names.map(function(name){
        return <div>{name}</div>
      })
    }
  </div>,
  document.getElementById("example")
)

上面的代码体现了JSX的基本语法规则:遇到HTML标签(以<开头),就用HTML规则解析,遇到代码块(以{开头),就用javascript语法解析

JSX允许直接在模板中插入javascript变量,如果这个变量是一个数组,则会展开这个数组的所有成员

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

上面代码的arr变量是一个数组,结果JSX把它的所有成员添加到模板,运行结果如下:

三、组件

React将代码封装成组件(Component),然后像插入普通html标签一样,在网页中插入这个组件,React.createClass方法就用于生成一个组件类

var HelloMessage = React.createClass({
  render: function(){
    return <h1>Hello,{this.props.name}</h1>
  }
})
ReactDOM.render(
  <HelloMessage name="孙俪"/>,
  document.getElementById("example")
)

上面代码,HelloMessage就是一个组件类,模板插入<HelloMessage />时,会自动生成一个HelloMessage的一个实例,所有组件类都必须有自己的render方法,用于输出组件

注意:组件类的第一个字母必须大写,否则会报错,比如:HelloMessage不能写成helloMessage。另外,组件类只能包含一个顶层标签,否则也会报错

 

var HelloMessage = React.createClass({
  render: function(){
    return <h1>Hello,{this.props.name}</h1>
    <p>哈哈</p>
  }
})
ReactDOM.render(
  <HelloMessage name="孙俪"/>,
  document.getElementById("example")
)

 

上面的代码会报错,因为组件类里面包含了两个顶层标签,h1 和 p。

组件的用法和原生的html标签完全一致,可以任意加入属性,比如,<HelloMessage name="Jone">组件加入了一个name属性,值为Jone,组件的属性可以在组件类的this.props对象上获取,比如,name属性就可以通过this.props.name读取。

在给组件类里的元素添加属性的时候,class属性需要写成className,for属性需要写成htmlFor,这是因为class和for都是javascript的保留字

四、this.props.children

this.props对象的属性和组件的属性一一对应,但是有一个例外,就是this.props.children属性。他表示组件的所有子节点

var NotesList = React.createClass({
    render: function(){
        return (
            <ol>
                {
                    React.Children.map(this.props.children,function(child){
                        return <li>{child}</li>
                    })
                }
            </ol>
        );
    }
})

ReactDOM.render(
    <NotesList>
        <span>hello</span>
        <span>world</span>
    </NotesList>,
    document.body
)

上面代码的NoteList组件有两个span子节点,他们都可以通过this.props.children读取,运行结果如下

这里需要注意,this.props.children的值有三种可能:如果当前组件没有子节点,他就是undefined;如果有一个子节点,数据类型是object;如果有多个子节点,数据类型就是array。所以,处理this.props.children的时候要小心。例如下面的例子,

 

var NoteList = React.createClass({
          render: function(){
             return (
                <ol>
                  {
                    this.props.children.map(function (child) {
                       return  <li>{child}</li>
                    })
                  }
                </ol>
            );
          }
        });

        ReactDOM.render(
          <NoteList>
              <span>工号</span>
          </NoteList>,
          document.body
        )

 

上面的代码由于组件的子节点只有一个span元素,是个object类型,所以会报错

 

React提供一个工具方法React.Children来处理this.props.children。我们可以用React.Children.map来遍历子节点,而不用担心this.props.children的数据类型是undeifned还是object。

六、PropTypes

组件的属性可以接受任意值,字符串、对象、函数等等都可以。有时,我们需要一种机制,验证别人使用组件时,提供的参数是否符合要求。

组件类的PropTypes属性,就是用来验证组件实例的属性是否符合要求。

var MyTitle = React.createClass({
    propTypes: {
        title:React.PropTypes.string.isReguired,
    },
    render: function() {
        return <h1>{this.props.title}</h1>
    }
})

上面的MyTitle组件有一个title属性。PropTypes告诉React,这个title属性是必须的,而且他的值必须是字符串。现在,我们设置title属性的值是一个数值

var data=123;
ReactDOM.render(
    <MyTitle title={data} />,
    document.body
)

这样一来,title属性就不通过验证了。控制台会显示一行错误信息。

 此外,getDefaultProps方法可以用来设置组件属性的默认值。

var MyTitle = React.createClass({
    getDefaultProps: function(){
        return {
            title: 'Hello World'
        };
    },
    render: function() {
        return <h1> {this.props.title} </h1>
    }
});

ReactDOM.render(
    <MyTitle />,
    document.body
)

上面代码会输出:"Hello World"。

六、获取真实的DOM节点

组件并不是真实的DOM节点,而是存在于内存之中的一种数据结构,叫做虚拟DOM。只有当他插入文档以后,才会变成真实的DOM。根据React的设计,所有的DOM变动,都先在虚拟DOM上发生,然后再将实际发生变动的部分,反映在真实DOM上,这种算法叫做DOM diff,它可以极大提高网页的性能表现。

但是,有时候需要从组建获取真实DOM的节点,这时候就要用到ref属性

var MyComponent = React.createClass({
    handleClick: function() {
        this.refs.myTextInput.focus();
    },
    render: function() {
        return (
            <div>
                <input type="text" ref="myTextInput" />
                <input type="button" value="Focus the text input" onClick={this.handleClick} />
            </div>
        );
    }
})

ReactDOM.render(
    <MyComponent></MyComponent>,
    document.body
)

上面代码中,组建MyComponent的子节点有一个文本输入框,用于获取用户的输入。这时就必须获取真实的DOM节点,虚拟DOM是拿不到用户输入的。为了做到这一点,文本输入框必须有一个ref属性,然后this.refs.[refName]就会返回这个真实的DOM节点。

需要注意的是,由于this.refs.[refName]属性获取的是真实DOM,所以必须等到虚拟DOM插入文档之后,才能使用这个属性,否则会报错。上面代码中,通过为组件指定click事件的回调函数,确保了只有等到真实DOM发生Click事件之后,才会读取this.refs.[refName]属性。

七、this.state

组件免不了要与用户互动,React的一大创新,就是将组件看成是一个状态机,一开始有一个初始状态,然后用户互动,导致状态变化,从而触发重新渲染UI

var LikeButton = React.createClass({
    getInitialState: function() {
        return {liked: false};
    },
    handleClick: function(event) {
        this.setState({liked: !this.state.liked});
    },
    render: function() {
        var text = this.state.liked ?'like':'haven\'t liked';
        return (
            <p onClick={this.handleClick}>
                You {text} this. Click to toggle.
            </p>
        )
    }
});
ReactDOM.render(
    <LikeButton />,
    document.body
)

上面代码是一个LikeButton组件,它的getInitialState方法用于定义初始状态,也就是一个对象,这个对象可以通过this.state属性读取,当用户点击组件,导致状态变化,this.setState方法就修改状态值,每次修改以后,自动调用this.render方法,再次渲染组件。

由于this.props和this.state都用于描述组件的特性,可能会产生混淆,一个简单的区分方法是,this.props表示哪些一旦定义,就不再改变的特性,而this.state是会随着用户互动而产生变化的特性。

posted @ 2017-07-26 15:50  吕瑞芳  阅读(263)  评论(0编辑  收藏  举报