走进Reac

走进React

  React是一个构建用户界面的JavaScript库,是Facebook公司在2013年5月在github上开源的。其特点如下:

  • 高效--React通过对DOM的模拟,最大程度地减少和DOM的交互。
  • JSX--它是对JavaScript的扩展,在React中可以不使用JSX,但是我们建议使用之。
  • 它主要是用于构建UI,很多人认为React是MVC中的V(视图)。

第一部分:React基本结构

  React的基本结构大致如下:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Hello React!</title>
    <script src="http://static.runoob.com/assets/react/react-0.14.7/build/react.min.js"></script>
    <script src="http://static.runoob.com/assets/react/react-0.14.7/build/react-dom.min.js"></script>
    <script src="http://static.runoob.com/assets/react/browser.min.js"></script>
  </head>
  <body>
    <div id="example"></div>
    <script type="text/babel">
      ReactDOM.render(
        <h1>Hello, world!</h1>,
        document.getElementById('example')
      );
    </script>
  </body>
</html>

  在这个React的基本结构里,我们需要明白三点:

  1. 无论怎么说,React也是一个js库,这里我们首先要加载三个js文件,其中react.min.js文件时React的核心文件;react-dom.min.js提供了与DOM相关的功能,之前我们也提到了“React通过对DOM的模拟,最大程度地减少和DOM的交互”;browser.min.js 可以将JSX语法转化为Javascript语法。
  2. 我们可以看到<script type="text/babel">其中的babel替换了我们十分熟悉的javascript,这是因为这里使用的JSX的语法,而不是JavaScript的语法,需格外注意。
  3. React和Babel他俩不是一回事,其中React是JavaScript的扩展,而Babel是一个编译器。他们两个的关系就是通过Babel我们可以把JSX转化为普通的JavaScript代码。
  4. 当然,React JSX代码也可以放在一个独立文件中,比如我们创建了一个myReact.js文件用于编写JSX代码,我们只需要这样引用<script type="text/babel"  src="./js/myReact.js">。

   另外这个例子得到的结果是显示 Hello world! 而ReactDOM.render()就是一个核心方法。React表明这是由React提供的方法,DOM表明此方法与DOM密切相关,render的因为是“渲染”。所以这里的意思就是将<h1>Hello,world!</h1>渲染到html中id为example下。值得注意的是,在JavaScript中对于html标签一定要打引号的,而这里没有使用引号,这也正体现了JSX的特别之处。但是JSX究竟是什么呢?它还有什么特别的用处呢?下面我们就可以对它了解。

 

 

第二部分:JSX

   JSX也是Facebook团队提出的一个语法方案,它可以在JavaScript的代码中直接使用HMTL标签来编写JavaScript对象。它是一个类似于XML的JavaScript语法扩展(JSX的全称即为JavaScriptXML),这种语法方案需要通过JSXTransformer来进行编译转换成真实可用的JavaScript代码。

  React是基于组件的开发思想,它认为组件是一个完全独立的没有任何其他依赖的模块文件,一个组件中可以有自己的样式(Inline Style)和结构(JSX编写的HTML)。 

  React使用JSX来代替常规的JavaScript,因为使用JSX后执行地更快,用它编写模版也非常简单。

  基本语法如下:

  1. 使用JSX来创建一个HTML标签,首字母小写:

var link = <href="#">Hello World</a>

  注意:这便是JSX语法,如果使用JavaScript,那么link变量值不可能是一个标签!!!

  上面的这句代码实际上相当于调用了React.createElement('a',{href:'#'},'Hello World!');于是我们可以看到React.createElement()方法接收三个参数:‘标签的名称’,{属性的名称:属性值},'标签的内容'。(注:显然React.createElement()方法是JavaScript语法,而var link = <href="#">Hello World</a>是JSX语法。具体我们可以这样使用:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>react.js</title>
     <script src="http://static.runoob.com/assets/react/react-0.14.7/build/react.min.js"></script>
    <script src="http://static.runoob.com/assets/react/react-0.14.7/build/react-dom.min.js"></script>
    <script src="http://static.runoob.com/assets/react/browser.min.js"></script>
</head>
<body>
    <div id="example"></div>
    <script type="text/babel">
        var link = <a href="#">Hello World</a>
        ReactDOM.render(
            link,
            document.getElementById('example')
        );
    </script>
</body>
</html>

  关于ReactDOM.render()方法后面会讲到,大致上说它是一个将html元素渲染的方法。 

  

  2.使用JSX来创建一个Component(组件,后面会详细讲解),首字母大写:

var HelloWorld = <HelloWorld foo="bar"></HelloWorld>

  注意:上面之所以严格要求区分首字母的大小写,这是因为这样JSX可以很简单的通过区分首字母的大小写来判断转换的是HTML标签还是自定义的Component标签。就像var a=5; 这里a显然是Number类型的,而var a = 'hello'; 显然这里的a就是string类型的,这样我们就无需再去判断了,从而更加简便。 

  

  3.JSX可以通过{变量名}这种形式来插入一个JavaScript变量。如下所示:

var variable = "World";
<a href="#"> hello {variable}!</a>

   于是我们竟然看到JavaScript语法和HTML语法完美结合!

 

  4.刚刚说了可以通过{变量名}来插入一个JavaScript变量,实际上,我们还可以通过{一个一次就能执行完的语句}在JSX中插入一个一次就能执行完成的JavaScript代码。也就是说:我们可以在JSX中使用JavaScript表达式,但表达式一定要写在{}中如下所示:

var link = <a href="#"> Hello {conditions ? 'zzw':''}! </a>;

  由于这是JSX语法,需要编译,编译之后得到的就是如下语法(显然编译得到的JS语法):

var link = React.createElement('a',{href:'#'},if(conditions){zzw});

   于是我们可以得到这样的一个结论:JSX的基本语法规则为:遇到HTML标签(以<开头),就用HTML规则解析;遇到代码块(以{开头)就用JavaScript规则解析。

 

  5.1 之前所说的都是单个标签的情况,如果有多个(语句)呢?这时应当注意:无论你的JSX代码有多长,每一段代码都只能有一个根节点,否则编译通过不了,如下所示:

var test = (
      <button>点击</button>
      <h1>错误的语法</h1> 
);

var test =<div>
        <button>点击</button>
        <h1>正确的语法</h1> 
      </div>
    );

  5.2 我们更常用的是ReactDOM.render()方法(这个方法也是JSX语法),它接受两个参数:第一个参数时html元素,如<h1>哈哈</h1>;第二个参数是获取一个元素,即要将第一个参数插入的地方,如document.getElementById("#ha");具体举例如下所示:

ReactDOM.render(
    <div>
    <h1>JSX学习</h1>
    <h2>React 学习</h2>
    <p data-myattribute = "somevalue">这是一个很不错的 JavaScript 库!</p>
    </div>
    ,
    document.getElementById('example')
);

  值得注意的是:这里我们添加了自定义属性data-myattribute,且添加自定义属性时一定要添加data-前缀。


 

 

  6.因为JSX可以直接将HTML写在JavaScript代码中,所以对于HTML中的属性可能会和JavaScript的关键字冲突,为避免冲突,我们必须做出相应的转变,如HTML的类class需要在JSX中写成className, 而for需要转化成htmlFor。

  

  7. 之前我们说过:React是基于组件的开发思想,它认为组件是一个完全独立的没有任何其他依赖的模块文件,一个组件中可以有自己的样式(Inline Style)和结构(JSX编写的HTML)。

   而之前我们已经介绍了使用JSX来直接编写HTML,这里我们将会把样式添加到这里组件中,举例如下所示:

 
 

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>react.js</title>
<script src="http://static.runoob.com/assets/react/react-0.14.7/build/react.min.js"></script>
<script src="http://static.runoob.com/assets/react/react-0.14.7/build/react-dom.min.js"></script>
<script src="http://static.runoob.com/assets/react/browser.min.js"></script>
</head>
<body>
<div ></div>
<script type="text/babel">
var myStyle = {
fontSize: 100,
color: '#FF0000'
};
ReactDOM.render(
<h1 style = {myStyle}>react学习</h1>,
document.getElementById('example')
);
</script>
</body>
</html>

 

  这里应当知道:mystyle是一个对象,所以var myStyle = 后面用的是花括号。 定义的inline_style对象中的属性名(key)就是样式的属性,如果该属性有“-”,那么我们应当将之转化为驼峰式,如本例中的fontSize,不需要写px,对于数字,会自动加上px,当然直接写成fontSize:100px'; 虽然这里把样式写成了内联的形式(在组件内部)违反了结构、表现相分离的原则,但是它却解决了因为分离带来的组件独立性的问题。

  

  8. JSX支持组件的命名空间。

  9.代码风格建议为了有更好的可读性,无论是单行语句还是多行语句,都建议使用()来包裹JSX语句。

 

  

第三部分:React组件

  组件是React的核心部分。

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

  先看下面的这个例子:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>react.js</title>
     <script src="http://static.runoob.com/assets/react/react-0.14.7/build/react.min.js"></script>
    <script src="http://static.runoob.com/assets/react/react-0.14.7/build/react-dom.min.js"></script>
    <script src="http://static.runoob.com/assets/react/browser.min.js"></script>
</head>
<body>
    <div id="example"></div>
    <script type="text/babel">
    var MyComponent = React.createClass({
        render:function(){
            return <h1> hello {this.props.name}! </h1>
        }
    });    
    
    ReactDOM.render(
        <MyComponent name="zhenwei"/>,
        document.getElementById('example')
    );
    </script>
</body>
</html>

  上面的代码中,变量MyComponent就是一个组件类。 模版插入<MyComponent/>(注意这里不需要写成‘开始标签+结束标签’的形式)时,就会自动生成MyComponent的一个实例,且所有的组件类都需要有自己的render方法,用于输出组件(即由render方法确定输入的组件实例的形式)。

   而其中的props是指所有的属性的集合(即属性properties的缩写形式),可以看作一个数组对象,本例的name只是props中的其中一个属性,还可以有其他的属性,如下例所示:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>react.js</title>
     <script src="http://static.runoob.com/assets/react/react-0.14.7/build/react.min.js"></script>
    <script src="http://static.runoob.com/assets/react/react-0.14.7/build/react-dom.min.js"></script>
    <script src="http://static.runoob.com/assets/react/browser.min.js"></script>
</head>
<body>
    <div id="example"></div>
    <script type="text/babel">
    var MyComponent = React.createClass({
        render:function(){
            return <h1> hello {this.props.name} , you are {this.props.gender} ! </h1>
        }
    });    
    
    ReactDOM.render(
        <div>
        <MyComponent name="zhenwei" gender="male"/>
        <MyComponent name="heting" gender="female"/>
        </div>,
        document.getElementById('example')
    );
    </script>
</body>
</html>

最终我们可以看到效果如下:

值得注意的是:在ReactDOM.render()中的两个组件实例必须由div包裹起来,因为在第一个参数中不得有两个根元素,否则会报错,如下面的形式就是错的

    ReactDOM.render(
        <MyComponent name="zhenwei" gender="male"/>
        <MyComponent name="heting" gender="female"/>
        ,
        document.getElementById('example')
    );

报错如下:

 

 

 

第四部分: React State(状态)

  我们可以将React的组件看成是一个状态机,一开始有一个初始状态,这时有一个对应的UI;然后用户和页面互动之后,导致状态发生了改变,从而触发从新渲染UI。如下例所示:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>React 实例</title>
    <script src="http://static.runoob.com/assets/react/react-0.14.7/build/react.min.js"></script>
    <script src="http://static.runoob.com/assets/react/react-0.14.7/build/react-dom.min.js"></script>
    <script src="http://static.runoob.com/assets/react/browser.min.js"></script>
  </head>
  <body>
    <div id="example"></div>
    <script type="text/babel">
    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.getElementById('example')
    );
    </script>
  </body>
</html>

  显然,在上面的代码中LikeButton是一个组件,其中getInitialState方法是固有的、React给我们提供的方法,用于定义这个“状态机”的初始状态,这个状态是一个对象,且我们可以通过this.state来改变;而handleClick方法是说当我们点击时,会自动切换两种状态。

这里需要注意的是:

  1. state即为组件的状态,我们也可以把它和props一样看作是数组对像,其中liked仅仅是这个数组对象中的其中一个属性,也就是说,state下面还可以有更多的属性。
  2. state和props的区别在于,props表示那些一旦定义就不会再改变的特性;而state表示那些会随着用户互动而改变的特性。

 

 

第五部分:this.props.children  

  该属性不同于this.props,它表示组件的所有子元素节点。并且React提供了一个方法即React.Child.map方法来遍历子元素节点,而不用担心this.props.children是undefined类型(当组件没有元素子节点时)、还是object类型(当组件有一个元素子节点时)、或者是array类型(当组件有两个及以上的元素子节点时)。因为React.Child.map方法可以很好地处理各种情况,举例如下所示:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>React 实例</title>
    <script src="http://static.runoob.com/assets/react/react-0.14.7/build/react.min.js"></script>
    <script src="http://static.runoob.com/assets/react/react-0.14.7/build/react-dom.min.js"></script>
    <script src="http://static.runoob.com/assets/react/browser.min.js"></script>
  </head>
  <body>
    <div id="example"></div>
    <script type="text/babel">
        var MyComponent = React.createClass({
            render:function(){
                return (
                    <ol>
                        {
                            React.Children.map(this.props.children,function(child){
                                 return    <li>{child}</li>;
                            })
                        }
                        {/*凡是出现js代码块的地方,我们都需要在外围添加 {} ,来告诉React如何去解析*/}
                    </ol>
                ); 
                {/*这里的return是一个语句,所以最后要添加分号*/} 
            }
                                     
        });
        ReactDOM.render(
            <MyComponent>
                <span>这是react</span>
                <span>这是JSX</span>
                <span>这是JavaScript</span>
            </MyComponent>
            ,
            document.body
        );
    </script>
  </body>
</html>

注意

  1. 我们在JSX中使用注释时,必须将注释包裹在{}中,即{/*这是一条注释*/}这样的形式。否则将会报错。
  2. 在return 之后,因为return的是<ol>这样的html标签,所以后面应当添加()来告诉React如何去解析,否则会报错。
  3. 由于render: function....这是一种类似函数声明的方式,所以最后是不可加分号的,否则会报错。这里也可以看作是创建的对象,因为该对象中只有一个属性,所以我们不需要在末尾添加符号。
  4. 遗留问题1:我在return ( 之后添加注释时,总会不错,不清楚是什么问题。
  5. 遗留问题2:我在render:function()...这个函数声明的末尾也无法成功添加注释。

 

 

 

第六部分:表单

  用户在表单中填入内容,这就是用户跟组件的互动,所以不能用this.props读取,因为我们之前说过“this.props表示那些一旦定义,就不能再改变的特性,而this.state是会随着用户互动而产生变化的特性”。所以这里要互动,就得使用this.state来跟组<!DOCT<html>

  <head>
    <meta charset="UTF-8" />
    <title>React 实例</title>
    <script src="http://static.runoob.com/assets/react/react-0.14.7/build/react.min.js"></script>
    <script src="http://static.runoob.com/assets/react/react-0.14.7/build/react-dom.min.js"></script>
    <script src="http://static.runoob.com/assets/react/browser.min.js"></script>
  </head>
  <body>
    <script type="text/babel">

  var Input = React.createClass({
      getInitialState: function() {
        return {value: ''};
      },
      handleChange: function(event) {
        this.setState({value: event.target.value});
     },
    render: function () {
       var value = this.state.value;
       var myStyle={
        width:'500px',
        height:'50px',
        fontSize:25,
        backgroundColor:'#ccc'
       };
       return (
         <div>
           <input type="text" value={value} style={myStyle} onChange={this.handleChange} />
           <h1>I will repeat the input:{value}</h1>
         </div>
       );
    }
});

ReactDOM.render(<Input/>, document.body);

    </script>
    
  </body>
</html>

React.createClass方法中因为包含的是JavaScript代码,所以需要用{}括起来,我们也能将之看作一个对象,有三个属性,而这三个属性又都是三个方法。

  其中getInitialState()方法用来设置初始状态;而handleChange()方法是用来处理change事件的,change事件被触发时,就会将event.target.value设置位当前的状态,而event.target即为触发这个事件的html元素,本例中即为input元素; 而render方法则是必须的,用来告诉浏览器如何将这个组件渲染,最终效果如下所示:
  

 

 

 

第七部分:组件的声明周期

  组件的声明周期可以分为以下三个状态:

  • Mounting:以插入真实DOM。 (注:mounting的中文意思即 增加,嵌入)
  • Updating: 正在被重新渲染。  (注:updating的中文意思即 更新)
  • Unmounting:已移出真实DOM    (注:unmounting即和mounting相反)

  React为每种状态提供了两种处理函数,will函数在进入状态之前使用,did函数在进入状态之后使用,三种状态可以有五种处理函数,如下所示:

  1. componentWillMount()  即组件插入时
  2. componentDidMount() 即组件插入后
  3. componentWillUpdate() 即组件更新时
  4. componentDidUpdate() 即组件更新后
  5. componentWillUnmount() 即组件移出时

  另外React还提供了两种特殊状态的处理函数:

  1. componentWillReceiveProps() 即当已加载组件接受到参数时调用
  2. shouldComponentUpdate() 即组件判断是否重新渲染时调用

  下面是一个与之相关的例子:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>react.js</title>
<script src="http://static.runoob.com/assets/react/react-0.14.7/build/react.min.js"></script>
<script src="http://static.runoob.com/assets/react/react-0.14.7/build/react-dom.min.js"></script>
<script src="http://static.runoob.com/assets/react/browser.min.js"></script>
<style>
.my_own_class{
font-size: 25px;
color:red;
}
</style>
</head>
<body>
<div >
<!-- This element's content will be replaced by your component. -->
</div>
<script type="text/babel">
var Hello = React.createClass({
getInitialState:function(){
alert("init");
return {
opacity:1.0,
fontSize:'22px',
color:'red'
};
{/*关键:上面返回的值我们一般可以通过this.state得到,显然,这样得到的是一个对象。*/}
},
render:function(){
return <div style={this.state} > Hello ,{this.props.name} </div>
},
componentWillMount:function(){
alert("will");
},
componentDidMount:function(){
alert('did');
var _self = this;
{/*这里之所以要把this赋值给_self,是因为这之前this指的是组件实例;而在window.setTimeout函数中时,this就指向了global全局环境,所以需要把this赋值给_self*/}
window.setTimeout(function(){
_self.setState({
opacity:0.3,
fontSize:'50px',
color:'blue'
});
},1000);
{/*显然,这一句代码被执行时,就处在了updating阶段*/}
}
});
{/* 注意:props一旦定义,一般不可再变化;然而state还是可以不断变化的。 */}

ReactDOM.render(
<Hello name="zhuzhenwei" />,
document.getElementById("container")
);
</script>
</body>
</html>

这一部分内容较为重要,我们可以参考慕课网视频,点击进入。

 

 

第八部分:事件监听、组件复用与获取dom的真实节点

    我们通过下面的这个例子来学习这一部分的知识内容,如下所示:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>react.js</title>
<script src="http://static.runoob.com/assets/react/react-0.14.7/build/react.min.js"></script>
<script src="http://static.runoob.com/assets/react/react-0.14.7/build/react-dom.min.js"></script>
<script src="http://static.runoob.com/assets/react/browser.min.js"></script>
<style>

</style>
</head>
<body>
<div id="container">
  <!-- This element's content will be replaced by your component. -->
</div>
<script type="text/babel">
  var  TestClickComponent = React.createClass({
      handleClick:function(event){
          var tipE=React.findDOMNode(this.refs.tip);
          {/* 上面这行代码的作用是拿到ref="tip" 的span的真实节点,其中 this.refs.tip只是虚拟节点,只有使用React.findDOMNode()方法才可以得到其真实节点。需要格外注意大小写,因为JSX是严格区分大小写的。*/}
          if(tipE.style.display==='none'){
              tipE.style.display='inline-block';
          }else{
              tipE.style.display='none';
          }
          event.stopPropagation();
          event.preventDefault();
      },
      render: function(){
          return (
            <div>
              <button onClick={this.handleClick}>显示|隐藏</button><span ref="tip">测试点击</span>
            </div>
          );   
      }
  });

  var  TestInputComponent = React.createClass({
      getInitialState:function(){
          return {
            inputContent:''
          };
      },
      changeHandler:function(event){
          this.setState({
            inputContent: event.target.value
          });
          {/*注意:this.setState()函数一定是需要在圆括号内添加花括号的,然后再添加需要设置的状态state*/}
          event.stopPropogation();
          event.preventDefault();
      },
      render: function(){
          return (
          <div>
            <input type="text" onChange={this.changeHandler}/> <span>{this.state.inputContent}</span>
            {/*这里绑定了onChange事件(由于这个虚拟节点,所以和纯粹的html是不同的),注意区分大小写。且一旦发生了onChange事件,就会回调this.changeHandler函数*/}
          </div>

          );
      }
  });


  React.render(<div><TestClickComponent/><br/><br/><br/><TestInputComponent/></div>,document.getElementById('container'));
  {/*
    注意:第一:React.render()函数中的第一个参数必须只能有一个顶层标签,所以我们需要使用div包裹起来。
          第二:这里我们使用了三个<br/>,这是为了在实验时更加地清楚,但是这违背了最佳实践---样式和结构的完全分离,在做项目的过程中,我们千万不能这么做!
  */}
</script>
</body>
</html>

  需要注意的地方在代码的注释中讲述的非常清楚。关于更多如何获取真实的节点可以看这篇文章。

 

 

 

 

第九部分:JSX的转换

  我们知道JSX是js的扩展,需要通过Babel编译之后才能使用。在之前的例子中,我们直接把JSX写在了<script type="text/babel"></script>之间,这样其自身就可以转换了。

  当然我们也可以手动转换,然后将JavaScript代码直接写在<script type="text/javascript"></script>之间。举例说明如下:

  第一步:将第八部分的JSX代码复制粘贴到 http://babeljs.io/ 中,在右半部分就可以得到js代码了。

  第二步:将js代码粘贴到<script type="text/javascript"></script>之间,即可正常使用。

 

 

 

 

参考资料

  http://www.ruanyifeng.com/blog/2015/03/react.html

  http://www.runoob.com/react/react-tutorial.html

  http://www.tuicool.com/articles/r2IJNr

推荐视频

  http://www.imooc.com/u/102030/courses?sort=publish

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值